diff options
author | Paul Mackerras <paulus@ozlabs.org> | 2017-08-30 06:12:38 +0200 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2017-09-01 08:39:55 +0200 |
commit | d955189ae42796621fb439e5e778ccaeebc2a1e7 (patch) | |
tree | edf5d221e3570203c1e46d660b8a8c9571bfb194 /arch/powerpc/include/asm | |
parent | powerpc: Set regs->dar if memory access fails in emulate_step() (diff) | |
download | linux-d955189ae42796621fb439e5e778ccaeebc2a1e7.tar.xz linux-d955189ae42796621fb439e5e778ccaeebc2a1e7.zip |
powerpc: Handle opposite-endian processes in emulation code
This adds code to the load and store emulation code to byte-swap
the data appropriately when the process being emulated is set to
the opposite endianness to that of the kernel.
This also enables the emulation for the multiple-register loads
and stores (lmw, stmw, lswi, stswi, lswx, stswx) to work for
little-endian. In little-endian mode, the partial word at the
end of a transfer for lsw*/stsw* (when the byte count is not a
multiple of 4) is loaded/stored at the least-significant end of
the register. Additionally, this fixes a bug in the previous
code in that it could call read_mem/write_mem with a byte count
that was not 1, 2, 4 or 8.
Note that this only works correctly on processors with "true"
little-endian mode, such as IBM POWER processors from POWER6 on, not
the so-called "PowerPC" little-endian mode that uses address swizzling
as implemented on the old 32-bit 603, 604, 740/750, 74xx CPUs.
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/include/asm')
-rw-r--r-- | arch/powerpc/include/asm/sstep.h | 7 |
1 files changed, 4 insertions, 3 deletions
diff --git a/arch/powerpc/include/asm/sstep.h b/arch/powerpc/include/asm/sstep.h index 793639a5aa5e..958c2c55bcfe 100644 --- a/arch/powerpc/include/asm/sstep.h +++ b/arch/powerpc/include/asm/sstep.h @@ -153,7 +153,8 @@ void emulate_update_regs(struct pt_regs *reg, struct instruction_op *op); extern int emulate_step(struct pt_regs *regs, unsigned int instr); extern void emulate_vsx_load(struct instruction_op *op, union vsx_reg *reg, - const void *mem); -extern void emulate_vsx_store(struct instruction_op *op, const union vsx_reg *reg, - void *mem); + const void *mem, bool cross_endian); +extern void emulate_vsx_store(struct instruction_op *op, + const union vsx_reg *reg, void *mem, + bool cross_endian); extern int emulate_dcbz(unsigned long ea, struct pt_regs *regs); |