1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-or-later */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2016 Imagination Technologies
4*4882a593Smuzhiyun * Author: Paul Burton <paul.burton@mips.com>
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #ifndef __MIPS_ASM_DSEMUL_H__
8*4882a593Smuzhiyun #define __MIPS_ASM_DSEMUL_H__
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <asm/break.h>
11*4882a593Smuzhiyun #include <asm/inst.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /* Break instruction with special math emu break code set */
14*4882a593Smuzhiyun #define BREAK_MATH(micromips) (((micromips) ? 0x7 : 0xd) | (BRK_MEMU << 16))
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun /* When used as a frame index, indicates the lack of a frame */
17*4882a593Smuzhiyun #define BD_EMUFRAME_NONE ((int)BIT(31))
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun struct mm_struct;
20*4882a593Smuzhiyun struct pt_regs;
21*4882a593Smuzhiyun struct task_struct;
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun /**
24*4882a593Smuzhiyun * mips_dsemul() - 'Emulate' an instruction from a branch delay slot
25*4882a593Smuzhiyun * @regs: User thread register context.
26*4882a593Smuzhiyun * @ir: The instruction to be 'emulated'.
27*4882a593Smuzhiyun * @branch_pc: The PC of the branch instruction.
28*4882a593Smuzhiyun * @cont_pc: The PC to continue at following 'emulation'.
29*4882a593Smuzhiyun *
30*4882a593Smuzhiyun * Emulate or execute an arbitrary MIPS instruction within the context of
31*4882a593Smuzhiyun * the current user thread. This is used primarily to handle instructions
32*4882a593Smuzhiyun * in the delay slots of emulated branch instructions, for example FP
33*4882a593Smuzhiyun * branch instructions on systems without an FPU.
34*4882a593Smuzhiyun *
35*4882a593Smuzhiyun * Return: Zero on success, negative if ir is a NOP, signal number on failure.
36*4882a593Smuzhiyun */
37*4882a593Smuzhiyun extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir,
38*4882a593Smuzhiyun unsigned long branch_pc, unsigned long cont_pc);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /**
41*4882a593Smuzhiyun * do_dsemulret() - Return from a delay slot 'emulation' frame
42*4882a593Smuzhiyun * @xcp: User thread register context.
43*4882a593Smuzhiyun *
44*4882a593Smuzhiyun * Call in response to the BRK_MEMU break instruction used to return to
45*4882a593Smuzhiyun * the kernel from branch delay slot 'emulation' frames following a call
46*4882a593Smuzhiyun * to mips_dsemul(). Restores the user thread PC to the value that was
47*4882a593Smuzhiyun * passed as the cpc parameter to mips_dsemul().
48*4882a593Smuzhiyun *
49*4882a593Smuzhiyun * Return: True if an emulation frame was returned from, else false.
50*4882a593Smuzhiyun */
51*4882a593Smuzhiyun #ifdef CONFIG_MIPS_FP_SUPPORT
52*4882a593Smuzhiyun extern bool do_dsemulret(struct pt_regs *xcp);
53*4882a593Smuzhiyun #else
do_dsemulret(struct pt_regs * xcp)54*4882a593Smuzhiyun static inline bool do_dsemulret(struct pt_regs *xcp)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun return false;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun #endif
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /**
61*4882a593Smuzhiyun * dsemul_thread_cleanup() - Cleanup thread 'emulation' frame
62*4882a593Smuzhiyun * @tsk: The task structure associated with the thread
63*4882a593Smuzhiyun *
64*4882a593Smuzhiyun * If the thread @tsk has a branch delay slot 'emulation' frame
65*4882a593Smuzhiyun * allocated to it then free that frame.
66*4882a593Smuzhiyun *
67*4882a593Smuzhiyun * Return: True if a frame was freed, else false.
68*4882a593Smuzhiyun */
69*4882a593Smuzhiyun #ifdef CONFIG_MIPS_FP_SUPPORT
70*4882a593Smuzhiyun extern bool dsemul_thread_cleanup(struct task_struct *tsk);
71*4882a593Smuzhiyun #else
dsemul_thread_cleanup(struct task_struct * tsk)72*4882a593Smuzhiyun static inline bool dsemul_thread_cleanup(struct task_struct *tsk)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun return false;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun #endif
77*4882a593Smuzhiyun /**
78*4882a593Smuzhiyun * dsemul_thread_rollback() - Rollback from an 'emulation' frame
79*4882a593Smuzhiyun * @regs: User thread register context.
80*4882a593Smuzhiyun *
81*4882a593Smuzhiyun * If the current thread, whose register context is represented by @regs,
82*4882a593Smuzhiyun * is executing within a delay slot 'emulation' frame then exit that
83*4882a593Smuzhiyun * frame. The PC will be rolled back to the branch if the instruction
84*4882a593Smuzhiyun * that was being 'emulated' has not yet executed, or advanced to the
85*4882a593Smuzhiyun * continuation PC if it has.
86*4882a593Smuzhiyun *
87*4882a593Smuzhiyun * Return: True if a frame was exited, else false.
88*4882a593Smuzhiyun */
89*4882a593Smuzhiyun #ifdef CONFIG_MIPS_FP_SUPPORT
90*4882a593Smuzhiyun extern bool dsemul_thread_rollback(struct pt_regs *regs);
91*4882a593Smuzhiyun #else
dsemul_thread_rollback(struct pt_regs * regs)92*4882a593Smuzhiyun static inline bool dsemul_thread_rollback(struct pt_regs *regs)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun return false;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun #endif
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /**
99*4882a593Smuzhiyun * dsemul_mm_cleanup() - Cleanup per-mm delay slot 'emulation' state
100*4882a593Smuzhiyun * @mm: The struct mm_struct to cleanup state for.
101*4882a593Smuzhiyun *
102*4882a593Smuzhiyun * Cleanup state for the given @mm, ensuring that any memory allocated
103*4882a593Smuzhiyun * for delay slot 'emulation' book-keeping is freed. This is to be called
104*4882a593Smuzhiyun * before @mm is freed in order to avoid memory leaks.
105*4882a593Smuzhiyun */
106*4882a593Smuzhiyun #ifdef CONFIG_MIPS_FP_SUPPORT
107*4882a593Smuzhiyun extern void dsemul_mm_cleanup(struct mm_struct *mm);
108*4882a593Smuzhiyun #else
dsemul_mm_cleanup(struct mm_struct * mm)109*4882a593Smuzhiyun static inline void dsemul_mm_cleanup(struct mm_struct *mm)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun /* no-op */
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun #endif
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun #endif /* __MIPS_ASM_DSEMUL_H__ */
116