diff options
author | Anshuman Khandual <khandual@linux.vnet.ibm.com> | 2015-07-29 10:10:02 +0300 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2015-08-12 08:04:52 +0300 |
commit | 79d0be7407955a268bcee5a33e338e14fdc74bfa (patch) | |
tree | e58dd02d7b1188ac5c2fd0c276a42275d730902e /arch/powerpc/mm/slb.c | |
parent | 2be682af48e8236558da702fe67e178cfe7524a1 (diff) | |
download | linux-79d0be7407955a268bcee5a33e338e14fdc74bfa.tar.xz |
powerpc/slb: Add documentation on runtime patching of SLB encoding
This patch adds some documentation to patch_slb_encoding() explaining
how it works.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
[mpe: Update change log and mention the signedness of the immediate]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/mm/slb.c')
-rw-r--r-- | arch/powerpc/mm/slb.c | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index faf9f0c4e823..8a32a2be3c53 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -249,7 +249,21 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) static inline void patch_slb_encoding(unsigned int *insn_addr, unsigned int immed) { - int insn = (*insn_addr & 0xffff0000) | immed; + + /* + * This function patches either an li or a cmpldi instruction with + * a new immediate value. This relies on the fact that both li + * (which is actually addi) and cmpldi both take a 16-bit immediate + * value, and it is situated in the same location in the instruction, + * ie. bits 16-31 (Big endian bit order) or the lower 16 bits. + * The signedness of the immediate operand differs between the two + * instructions however this code is only ever patching a small value, + * much less than 1 << 15, so we can get away with it. + * To patch the value we read the existing instruction, clear the + * immediate value, and or in our new value, then write the instruction + * back. + */ + unsigned int insn = (*insn_addr & 0xffff0000) | immed; patch_instruction(insn_addr, insn); } |