[PATCH] arm64/alternatives: use subsections for replacement sequences

Ard Biesheuvel ardb at kernel.org
Thu Jul 9 08:39:53 EDT 2020


On Thu, 9 Jul 2020 at 15:31, Ard Biesheuvel <ardb at kernel.org> wrote:
>
> On Thu, 9 Jul 2020 at 14:11, Alexandru Elisei <alexandru.elisei at arm.com> wrote:
> >
> > Hi,
> >
>
> Hi Alex,
>
> Apologies for the breakage.
>
>
> > I should post the entire boot log:
> ...
> > [    0.002204] pc : work_pending+0x32c/0x348
>
> This suggests that you ended executing directly from the alternatives
> replacement section that gets appended to the end of work_pending (and
> therefore gets mistaken for being part of it)
>
> It appears that the following code in alternatives.c
>
> static bool branch_insn_requires_update(struct alt_instr *alt, unsigned long pc)
> {
>     unsigned long replptr;
>
>     if (kernel_text_address(pc))
>        return true;
>
> returns true inadvertently for the branch in this piece of code in entry.S
>
> alternative_if ARM64_HAS_IRQ_PRIO_MASKING
>     ldr x20, [sp, #S_PMR_SAVE]
>     msr_s SYS_ICC_PMR_EL1, x20
>     mrs_s x21, SYS_ICC_CTLR_EL1
>     tbz x21, #6, .L__skip_pmr_sync\@ // Check for ICC_CTLR_EL1.PMHE
>     dsb sy // Ensure priority change is seen by redistributor
> .L__skip_pmr_sync\@:
>
>
> due to the fact that kernel_text_address() has no way of
> distinguishing branches inside the subsection from branches that
> require updating. So the alternatives patching code dutifully updates
> the tbz opcode and points it to its original target in the subsection.
>
> This is going to be rather tricky to fix, unless we special case
> tbz/cbz branches and other branches with limited range that would
> never have worked before anyway.
>
> For now, better to just revert it and revisit it later.
>

... unless we decide to fix up all branches pointing outside the
replacement sequence, which is not an entirely unreasonable thing to
do:

diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
index d1757ef1b1e7..7c205f9202a3 100644
--- a/arch/arm64/kernel/alternative.c
+++ b/arch/arm64/kernel/alternative.c
@@ -45,18 +45,11 @@
 {
        unsigned long replptr;

-       if (kernel_text_address(pc))
-               return true;
-
        replptr = (unsigned long)ALT_REPL_PTR(alt);
        if (pc >= replptr && pc <= (replptr + alt->alt_len))
                return false;

-       /*
-        * Branching into *another* alternate sequence is doomed, and
-        * we're not even trying to fix it up.
-        */
-       BUG();
+       return true;
 }



More information about the linux-arm-kernel mailing list