mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
4f82590078
Use the existing support for testing compute type instructions to test Prefixed Add Immediate (paddi). The R bit of the paddi instruction controls whether current instruction address is used. Add test cases for when R=1 and for R=0. paddi has a 34 bit immediate field formed by concatenating si0 and si1. Add tests for the extreme values of this field. Skip the paddi tests if ISA v3.1 is unsupported. Some of these test cases were added by Balamuruhan S. Signed-off-by: Jordan Niethe <jniethe5@gmail.com> [mpe: Fix conflicts with ppc-opcode.h changes, squash in .balign] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20200525025923.19843-5-jniethe5@gmail.com
153 lines
3.5 KiB
ArmAsm
153 lines
3.5 KiB
ArmAsm
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Non-emulated single-stepping support (currently limited to basic integer
|
|
* computations) used to validate the instruction emulation infrastructure.
|
|
*
|
|
* Copyright (C) 2019 IBM Corporation
|
|
*/
|
|
|
|
#include <asm/asm-offsets.h>
|
|
#include <asm/ppc_asm.h>
|
|
#include <asm/code-patching-asm.h>
|
|
#include <linux/errno.h>
|
|
|
|
/* int exec_instr(struct pt_regs *regs) */
|
|
_GLOBAL(exec_instr)
|
|
|
|
/*
|
|
* Stack frame layout (INT_FRAME_SIZE bytes)
|
|
* In-memory pt_regs (SP + STACK_FRAME_OVERHEAD)
|
|
* Scratch space (SP + 8)
|
|
* Back chain (SP + 0)
|
|
*/
|
|
|
|
/*
|
|
* Allocate a new stack frame with enough space to hold the register
|
|
* states in an in-memory pt_regs and also create the back chain to
|
|
* the caller's stack frame.
|
|
*/
|
|
stdu r1, -INT_FRAME_SIZE(r1)
|
|
|
|
/*
|
|
* Save non-volatile GPRs on stack. This includes TOC pointer (GPR2)
|
|
* and local variables (GPR14 to GPR31). The register for the pt_regs
|
|
* parameter (GPR3) is saved additionally to ensure that the resulting
|
|
* register state can still be saved even if GPR3 gets overwritten
|
|
* when loading the initial register state for the test instruction.
|
|
* The stack pointer (GPR1) and the thread pointer (GPR13) are not
|
|
* saved as these should not be modified anyway.
|
|
*/
|
|
SAVE_2GPRS(2, r1)
|
|
SAVE_NVGPRS(r1)
|
|
|
|
/*
|
|
* Save LR on stack to ensure that the return address is available
|
|
* even if it gets overwritten by the test instruction.
|
|
*/
|
|
mflr r0
|
|
std r0, _LINK(r1)
|
|
|
|
/*
|
|
* Save CR on stack. For simplicity, the entire register is saved
|
|
* even though only fields 2 to 4 are non-volatile.
|
|
*/
|
|
mfcr r0
|
|
std r0, _CCR(r1)
|
|
|
|
/*
|
|
* Load register state for the test instruction without touching the
|
|
* critical non-volatile registers. The register state is passed as a
|
|
* pointer to a pt_regs instance.
|
|
*/
|
|
subi r31, r3, GPR0
|
|
|
|
/* Load LR from pt_regs */
|
|
ld r0, _LINK(r31)
|
|
mtlr r0
|
|
|
|
/* Load CR from pt_regs */
|
|
ld r0, _CCR(r31)
|
|
mtcr r0
|
|
|
|
/* Load XER from pt_regs */
|
|
ld r0, _XER(r31)
|
|
mtxer r0
|
|
|
|
/* Load GPRs from pt_regs */
|
|
REST_GPR(0, r31)
|
|
REST_10GPRS(2, r31)
|
|
REST_GPR(12, r31)
|
|
REST_NVGPRS(r31)
|
|
|
|
/* Placeholder for the test instruction */
|
|
.balign 64
|
|
1: nop
|
|
nop
|
|
patch_site 1b patch__exec_instr
|
|
|
|
/*
|
|
* Since GPR3 is overwritten, temporarily restore it back to its
|
|
* original state, i.e. the pointer to pt_regs, to ensure that the
|
|
* resulting register state can be saved. Before doing this, a copy
|
|
* of it is created in the scratch space which is used later on to
|
|
* save it to pt_regs.
|
|
*/
|
|
std r3, 8(r1)
|
|
REST_GPR(3, r1)
|
|
|
|
/* Save resulting GPR state to pt_regs */
|
|
subi r3, r3, GPR0
|
|
SAVE_GPR(0, r3)
|
|
SAVE_GPR(2, r3)
|
|
SAVE_8GPRS(4, r3)
|
|
SAVE_GPR(12, r3)
|
|
SAVE_NVGPRS(r3)
|
|
|
|
/* Save resulting LR to pt_regs */
|
|
mflr r0
|
|
std r0, _LINK(r3)
|
|
|
|
/* Save resulting CR to pt_regs */
|
|
mfcr r0
|
|
std r0, _CCR(r3)
|
|
|
|
/* Save resulting XER to pt_regs */
|
|
mfxer r0
|
|
std r0, _XER(r3)
|
|
|
|
/* Restore resulting GPR3 from scratch space and save it to pt_regs */
|
|
ld r0, 8(r1)
|
|
std r0, GPR3(r3)
|
|
|
|
/* Set return value to denote execution success */
|
|
li r3, 0
|
|
|
|
/* Continue */
|
|
b 3f
|
|
|
|
/* Set return value to denote execution failure */
|
|
2: li r3, -EFAULT
|
|
|
|
/* Restore the non-volatile GPRs from stack */
|
|
3: REST_GPR(2, r1)
|
|
REST_NVGPRS(r1)
|
|
|
|
/* Restore LR from stack to be able to return */
|
|
ld r0, _LINK(r1)
|
|
mtlr r0
|
|
|
|
/* Restore CR from stack */
|
|
ld r0, _CCR(r1)
|
|
mtcr r0
|
|
|
|
/* Tear down stack frame */
|
|
addi r1, r1, INT_FRAME_SIZE
|
|
|
|
/* Return */
|
|
blr
|
|
|
|
/* Setup exception table */
|
|
EX_TABLE(1b, 2b)
|
|
|
|
_ASM_NOKPROBE_SYMBOL(exec_instr)
|