]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
parisc: Split out alternative live patching code
authorHelge Deller <deller@gmx.de>
Sat, 10 Nov 2018 15:14:59 +0000 (16:14 +0100)
committerHelge Deller <deller@gmx.de>
Mon, 10 Dec 2018 06:47:50 +0000 (07:47 +0100)
Move the alternative implemenation coding to alternative.c and add code to
patch modules while loading.

Signed-off-by: Helge Deller <deller@gmx.de>
arch/parisc/include/asm/alternative.h
arch/parisc/kernel/Makefile
arch/parisc/kernel/alternative.c [new file with mode: 0644]
arch/parisc/kernel/module.c
arch/parisc/kernel/setup.c

index bf485a94d0b4b8697b699e6ddc99d4e33b3d7f6a..793d8baa3a10d136e6f23a2aea8dcf4bf5d65b73 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef __ASM_PARISC_ALTERNATIVE_H
 #define __ASM_PARISC_ALTERNATIVE_H
 
+#define ALT_COND_ALWAYS                0x80    /* always replace instruction */
 #define ALT_COND_NO_SMP                0x01    /* when running UP instead of SMP */
 #define ALT_COND_NO_DCACHE     0x02    /* if system has no d-cache  */
 #define ALT_COND_NO_ICACHE     0x04    /* if system has no i-cache  */
@@ -26,6 +27,9 @@ struct alt_instr {
 };
 
 void set_kernel_text_rw(int enable_read_write);
+void apply_alternatives_all(void);
+void apply_alternatives(struct alt_instr *start, struct alt_instr *end,
+       const char *module_name);
 
 /* Alternative SMP implementation. */
 #define ALTERNATIVE(cond, replacement)         "!0:"   \
index e5de34d00b1adad3409bd11b07fae826167e59c5..8e5f1ab65c68d493198c55937639de24e21fa7d2 100644 (file)
@@ -7,7 +7,7 @@ extra-y                 := head.o vmlinux.lds
 
 obj-y          := cache.o pacache.o setup.o pdt.o traps.o time.o irq.o \
                   pa7300lc.o syscall.o entry.o sys_parisc.o firmware.o \
-                  ptrace.o hardware.o inventory.o drivers.o \
+                  ptrace.o hardware.o inventory.o drivers.o alternative.o \
                   signal.o hpmc.o real2.o parisc_ksyms.o unaligned.o \
                   process.o processor.o pdc_cons.o pdc_chassis.o unwind.o
 
diff --git a/arch/parisc/kernel/alternative.c b/arch/parisc/kernel/alternative.c
new file mode 100644 (file)
index 0000000..bf2274e
--- /dev/null
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *    Alternative live-patching for parisc.
+ *    Copyright (C) 2018 Helge Deller <deller@gmx.de>
+ *
+ */
+
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/alternative.h>
+
+#include <linux/module.h>
+
+static int no_alternatives;
+static int __init setup_no_alternatives(char *str)
+{
+       no_alternatives = 1;
+       return 1;
+}
+__setup("no-alternatives", setup_no_alternatives);
+
+void __init_or_module apply_alternatives(struct alt_instr *start,
+                struct alt_instr *end, const char *module_name)
+{
+       struct alt_instr *entry;
+       int index = 0, applied = 0;
+       int num_cpus = num_online_cpus();
+
+       for (entry = start; entry < end; entry++, index++) {
+
+               u32 *from, len, cond, replacement;
+
+               from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset);
+               len = entry->len;
+               cond = entry->cond;
+               replacement = entry->replacement;
+
+               WARN_ON(!cond);
+
+               if (cond != ALT_COND_ALWAYS && no_alternatives)
+                       continue;
+
+               pr_debug("Check %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n",
+                       index, cond, len, from, replacement);
+
+               if ((cond & ALT_COND_NO_SMP) && (num_cpus != 1))
+                       continue;
+               if ((cond & ALT_COND_NO_DCACHE) && (cache_info.dc_size != 0))
+                       continue;
+               if ((cond & ALT_COND_NO_ICACHE) && (cache_info.ic_size != 0))
+                       continue;
+
+               /*
+                * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit
+                * set (bit #61, big endian), we have to flush and sync every
+                * time IO-PDIR is changed in Ike/Astro.
+                */
+               if ((cond & ALT_COND_NO_IOC_FDC) &&
+                       (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC))
+                       continue;
+
+               /* Want to replace pdtlb by a pdtlb,l instruction? */
+               if (replacement == INSN_PxTLB) {
+                       replacement = *from;
+                       if (boot_cpu_data.cpu_type >= pcxu) /* >= pa2.0 ? */
+                               replacement |= (1 << 10); /* set el bit */
+               }
+
+               /*
+                * Replace instruction with NOPs?
+                * For long distance insert a branch instruction instead.
+                */
+               if (replacement == INSN_NOP && len > 1)
+                       replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */
+
+               pr_debug("Do    %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n",
+                       index, cond, len, from, replacement);
+
+               /* Replace instruction */
+               *from = replacement;
+               applied++;
+       }
+
+       pr_info("%s%salternatives: applied %d out of %d patches\n",
+               module_name ? : "", module_name ? " " : "",
+               applied, index);
+}
+
+
+void __init apply_alternatives_all(void)
+{
+       set_kernel_text_rw(1);
+
+       apply_alternatives((struct alt_instr *) &__alt_instructions,
+               (struct alt_instr *) &__alt_instructions_end, NULL);
+
+       set_kernel_text_rw(0);
+}
index b5b3cb00f1fb0f4cb2368812c461a9821350c48f..43778420614b15c67a8295aeacf7f8036c6d6ccf 100644 (file)
@@ -877,6 +877,8 @@ int module_finalize(const Elf_Ehdr *hdr,
        int i;
        unsigned long nsyms;
        const char *strtab = NULL;
+       const Elf_Shdr *s;
+       char *secstrings;
        Elf_Sym *newptr, *oldptr;
        Elf_Shdr *symhdr = NULL;
 #ifdef DEBUG
@@ -948,6 +950,18 @@ int module_finalize(const Elf_Ehdr *hdr,
        nsyms = newptr - (Elf_Sym *)symhdr->sh_addr;
        DEBUGP("NEW num_symtab %lu\n", nsyms);
        symhdr->sh_size = nsyms * sizeof(Elf_Sym);
+
+       /* find .altinstructions section */
+       secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+       for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
+               void *aseg = (void *) s->sh_addr;
+               char *secname = secstrings + s->sh_name;
+
+               if (!strcmp(".altinstructions", secname))
+                       /* patch .altinstructions */
+                       apply_alternatives(aseg, aseg + s->sh_size, me->name);
+       }
+
        return 0;
 }
 
index cd227f1cf629e0c1aa926d0029ad1706910958a6..2b108ee3b2176b8f23637f563da451fdc140d00d 100644 (file)
@@ -305,86 +305,6 @@ static int __init parisc_init_resources(void)
        return 0;
 }
 
-static int no_alternatives __initdata;
-static int __init setup_no_alternatives(char *str)
-{
-       no_alternatives = 1;
-       return 1;
-}
-__setup("no-alternatives", setup_no_alternatives);
-
-static void __init apply_alternatives_all(void)
-{
-       struct alt_instr *entry;
-       int index = 0, applied = 0;
-
-
-       pr_info("alternatives: %spatching kernel code\n",
-               no_alternatives ? "NOT " : "");
-       if (no_alternatives)
-               return;
-
-       set_kernel_text_rw(1);
-
-       for (entry = (struct alt_instr *) &__alt_instructions;
-               entry < (struct alt_instr *) &__alt_instructions_end;
-               entry++, index++) {
-
-               u32 *from, len, cond, replacement;
-
-               from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset);
-               len = entry->len;
-               cond = entry->cond;
-               replacement = entry->replacement;
-
-               WARN_ON(!cond);
-               pr_debug("Check %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n",
-                       index, cond, len, from, replacement);
-
-               if ((cond & ALT_COND_NO_SMP) && (num_online_cpus() != 1))
-                       continue;
-               if ((cond & ALT_COND_NO_DCACHE) && (cache_info.dc_size != 0))
-                       continue;
-               if ((cond & ALT_COND_NO_ICACHE) && (cache_info.ic_size != 0))
-                       continue;
-
-               /*
-                * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit
-                * set (bit #61, big endian), we have to flush and sync every
-                * time IO-PDIR is changed in Ike/Astro.
-                */
-               if ((cond & ALT_COND_NO_IOC_FDC) &&
-                       (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC))
-                       continue;
-
-               /* Want to replace pdtlb by a pdtlb,l instruction? */
-               if (replacement == INSN_PxTLB) {
-                       replacement = *from;
-                       if (boot_cpu_data.cpu_type >= pcxu) /* >= pa2.0 ? */
-                               replacement |= (1 << 10); /* set el bit */
-               }
-
-               /*
-                * Replace instruction with NOPs?
-                * For long distance insert a branch instruction instead.
-                */
-               if (replacement == INSN_NOP && len > 1)
-                       replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */
-
-               pr_debug("Do    %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n",
-                       index, cond, len, from, replacement);
-
-               /* Replace instruction */
-               *from = replacement;
-               applied++;
-       }
-
-       pr_info("alternatives: applied %d out of %d patches\n", applied, index);
-
-       set_kernel_text_rw(0);
-}
-
-
 extern void gsc_init(void);
 extern void processor_init(void);
 extern void ccio_init(void);