aboutsummaryrefslogtreecommitdiffstats
path: root/arch/parisc
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2019-08-12 13:11:06 -0400
committerHelge Deller <deller@gmx.de>2019-08-12 13:17:39 -0400
commit82992fc70f98dee091faa926eb5cecadda5c84f4 (patch)
tree915078a06f9ed8bd736bbd29d52eca237af19b91 /arch/parisc
parent83af58f8068ea3f7b3c537c37a30887bfa585069 (diff)
parisc: Add ALTERNATIVE_CODE() and ALT_COND_RUN_ON_QEMU
The macro ALTERNATIVE_CODE() allows assembly code to patch in a series of new assembler statements given at a specific start address. The ALT_COND_RUN_ON_QEMU condition is true if the kernel is started in a qemu emulation. Signed-off-by: Helge Deller <deller@gmx.de>
Diffstat (limited to 'arch/parisc')
-rw-r--r--arch/parisc/include/asm/alternative.h11
-rw-r--r--arch/parisc/kernel/alternative.c23
2 files changed, 27 insertions, 7 deletions
diff --git a/arch/parisc/include/asm/alternative.h b/arch/parisc/include/asm/alternative.h
index 793d8baa3a10..0ec54f43d6d2 100644
--- a/arch/parisc/include/asm/alternative.h
+++ b/arch/parisc/include/asm/alternative.h
@@ -8,6 +8,7 @@
8#define ALT_COND_NO_ICACHE 0x04 /* if system has no i-cache */ 8#define ALT_COND_NO_ICACHE 0x04 /* if system has no i-cache */
9#define ALT_COND_NO_SPLIT_TLB 0x08 /* if split_tlb == 0 */ 9#define ALT_COND_NO_SPLIT_TLB 0x08 /* if split_tlb == 0 */
10#define ALT_COND_NO_IOC_FDC 0x10 /* if I/O cache does not need flushes */ 10#define ALT_COND_NO_IOC_FDC 0x10 /* if I/O cache does not need flushes */
11#define ALT_COND_RUN_ON_QEMU 0x20 /* if running on QEMU */
11 12
12#define INSN_PxTLB 0x02 /* modify pdtlb, pitlb */ 13#define INSN_PxTLB 0x02 /* modify pdtlb, pitlb */
13#define INSN_NOP 0x08000240 /* nop */ 14#define INSN_NOP 0x08000240 /* nop */
@@ -21,7 +22,7 @@
21 22
22struct alt_instr { 23struct alt_instr {
23 s32 orig_offset; /* offset to original instructions */ 24 s32 orig_offset; /* offset to original instructions */
24 u32 len; /* end of original instructions */ 25 s32 len; /* end of original instructions */
25 u32 cond; /* see ALT_COND_XXX */ 26 u32 cond; /* see ALT_COND_XXX */
26 u32 replacement; /* replacement instruction or code */ 27 u32 replacement; /* replacement instruction or code */
27}; 28};
@@ -40,12 +41,20 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end,
40 41
41#else 42#else
42 43
44/* to replace one single instructions by a new instruction */
43#define ALTERNATIVE(from, to, cond, replacement)\ 45#define ALTERNATIVE(from, to, cond, replacement)\
44 .section .altinstructions, "aw" ! \ 46 .section .altinstructions, "aw" ! \
45 .word (from - .), (to - from)/4 ! \ 47 .word (from - .), (to - from)/4 ! \
46 .word cond, replacement ! \ 48 .word cond, replacement ! \
47 .previous 49 .previous
48 50
51/* to replace multiple instructions by new code */
52#define ALTERNATIVE_CODE(from, num_instructions, cond, new_instr_ptr)\
53 .section .altinstructions, "aw" ! \
54 .word (from - .), -num_instructions ! \
55 .word cond, (new_instr_ptr - .) ! \
56 .previous
57
49#endif /* __ASSEMBLY__ */ 58#endif /* __ASSEMBLY__ */
50 59
51#endif /* __ASM_PARISC_ALTERNATIVE_H */ 60#endif /* __ASM_PARISC_ALTERNATIVE_H */
diff --git a/arch/parisc/kernel/alternative.c b/arch/parisc/kernel/alternative.c
index ca1f5ca0540a..3c66d5c4d90d 100644
--- a/arch/parisc/kernel/alternative.c
+++ b/arch/parisc/kernel/alternative.c
@@ -28,7 +28,8 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
28 28
29 for (entry = start; entry < end; entry++, index++) { 29 for (entry = start; entry < end; entry++, index++) {
30 30
31 u32 *from, len, cond, replacement; 31 u32 *from, cond, replacement;
32 s32 len;
32 33
33 from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset); 34 from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset);
34 len = entry->len; 35 len = entry->len;
@@ -49,6 +50,8 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
49 continue; 50 continue;
50 if ((cond & ALT_COND_NO_ICACHE) && (cache_info.ic_size != 0)) 51 if ((cond & ALT_COND_NO_ICACHE) && (cache_info.ic_size != 0))
51 continue; 52 continue;
53 if ((cond & ALT_COND_RUN_ON_QEMU) && !running_on_qemu)
54 continue;
52 55
53 /* 56 /*
54 * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit 57 * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit
@@ -74,11 +77,19 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
74 if (replacement == INSN_NOP && len > 1) 77 if (replacement == INSN_NOP && len > 1)
75 replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */ 78 replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */
76 79
77 pr_debug("Do %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n", 80 pr_debug("ALTERNATIVE %3d: Cond %2x, Replace %2d instructions to 0x%08x @ 0x%px (%pS)\n",
78 index, cond, len, from, replacement); 81 index, cond, len, replacement, from, from);
79 82
80 /* Replace instruction */ 83 if (len < 0) {
81 *from = replacement; 84 /* Replace multiple instruction by new code */
85 u32 *source;
86 len = -len;
87 source = (u32 *)((ulong)&entry->replacement + entry->replacement);
88 memcpy(from, source, 4 * len);
89 } else {
90 /* Replace by one instruction */
91 *from = replacement;
92 }
82 applied++; 93 applied++;
83 } 94 }
84 95