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>
This commit is contained in:
Helge Deller 2019-08-12 19:11:06 +02:00
parent 83af58f806
commit 82992fc70f
2 changed files with 26 additions and 6 deletions

View File

@ -8,6 +8,7 @@
#define ALT_COND_NO_ICACHE 0x04 /* if system has no i-cache */ #define ALT_COND_NO_ICACHE 0x04 /* if system has no i-cache */
#define ALT_COND_NO_SPLIT_TLB 0x08 /* if split_tlb == 0 */ #define ALT_COND_NO_SPLIT_TLB 0x08 /* if split_tlb == 0 */
#define ALT_COND_NO_IOC_FDC 0x10 /* if I/O cache does not need flushes */ #define ALT_COND_NO_IOC_FDC 0x10 /* if I/O cache does not need flushes */
#define ALT_COND_RUN_ON_QEMU 0x20 /* if running on QEMU */
#define INSN_PxTLB 0x02 /* modify pdtlb, pitlb */ #define INSN_PxTLB 0x02 /* modify pdtlb, pitlb */
#define INSN_NOP 0x08000240 /* nop */ #define INSN_NOP 0x08000240 /* nop */
@ -21,7 +22,7 @@
struct alt_instr { struct alt_instr {
s32 orig_offset; /* offset to original instructions */ s32 orig_offset; /* offset to original instructions */
u32 len; /* end of original instructions */ s32 len; /* end of original instructions */
u32 cond; /* see ALT_COND_XXX */ u32 cond; /* see ALT_COND_XXX */
u32 replacement; /* replacement instruction or code */ u32 replacement; /* replacement instruction or code */
}; };
@ -40,12 +41,20 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end,
#else #else
/* to replace one single instructions by a new instruction */
#define ALTERNATIVE(from, to, cond, replacement)\ #define ALTERNATIVE(from, to, cond, replacement)\
.section .altinstructions, "aw" ! \ .section .altinstructions, "aw" ! \
.word (from - .), (to - from)/4 ! \ .word (from - .), (to - from)/4 ! \
.word cond, replacement ! \ .word cond, replacement ! \
.previous .previous
/* to replace multiple instructions by new code */
#define ALTERNATIVE_CODE(from, num_instructions, cond, new_instr_ptr)\
.section .altinstructions, "aw" ! \
.word (from - .), -num_instructions ! \
.word cond, (new_instr_ptr - .) ! \
.previous
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* __ASM_PARISC_ALTERNATIVE_H */ #endif /* __ASM_PARISC_ALTERNATIVE_H */

View File

@ -28,7 +28,8 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
for (entry = start; entry < end; entry++, index++) { for (entry = start; entry < end; entry++, index++) {
u32 *from, len, cond, replacement; u32 *from, cond, replacement;
s32 len;
from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset); from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset);
len = entry->len; len = entry->len;
@ -49,6 +50,8 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
continue; continue;
if ((cond & ALT_COND_NO_ICACHE) && (cache_info.ic_size != 0)) if ((cond & ALT_COND_NO_ICACHE) && (cache_info.ic_size != 0))
continue; continue;
if ((cond & ALT_COND_RUN_ON_QEMU) && !running_on_qemu)
continue;
/* /*
* If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit * 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,
if (replacement == INSN_NOP && len > 1) if (replacement == INSN_NOP && len > 1)
replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */ replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */
pr_debug("Do %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n", pr_debug("ALTERNATIVE %3d: Cond %2x, Replace %2d instructions to 0x%08x @ 0x%px (%pS)\n",
index, cond, len, from, replacement); index, cond, len, replacement, from, from);
/* Replace instruction */ if (len < 0) {
*from = replacement; /* Replace multiple instruction by new code */
u32 *source;
len = -len;
source = (u32 *)((ulong)&entry->replacement + entry->replacement);
memcpy(from, source, 4 * len);
} else {
/* Replace by one instruction */
*from = replacement;
}
applied++; applied++;
} }