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:
parent
83af58f806
commit
82992fc70f
|
@ -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 */
|
||||||
|
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue