#define __NR_syscall 4000
#endif
+static inline bool mips_syscall_is_indirect(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
+ return (IS_ENABLED(CONFIG_32BIT) ||
+ test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
+ (regs->regs[2] == __NR_syscall);
+}
+
static inline long syscall_get_nr(struct task_struct *task,
struct pt_regs *regs)
{
return current_thread_info()->syscall;
}
+static inline void mips_syscall_update_nr(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ /*
+ * v0 is the system call number, except for O32 ABI syscall(), where it
+ * ends up in a0.
+ */
+ if (mips_syscall_is_indirect(task, regs))
+ task_thread_info(task)->syscall = regs->regs[4];
+ else
+ task_thread_info(task)->syscall = regs->regs[2];
+}
+
static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
struct task_struct *task, struct pt_regs *regs, unsigned int n)
{
unsigned long *args)
{
int ret;
- /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
- if ((IS_ENABLED(CONFIG_32BIT) ||
- test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
- (regs->regs[2] == __NR_syscall))
+
+ /* O32 ABI syscall() */
+ if (mips_syscall_is_indirect(task, regs))
i++;
while (n--)
/* badvaddr, status, and cause may not be written. */
+ /* System call number may have been changed */
+ mips_syscall_update_nr(child, regs);
+
return 0;
}
}
}
+ /* System call number may have been changed */
+ mips_syscall_update_nr(target, regs);
+
return 0;
}
}
}
+ /* System call number may have been changed */
+ mips_syscall_update_nr(target, regs);
+
return 0;
}
switch (addr) {
case 0 ... 31:
regs->regs[addr] = data;
+ /* System call number may have been changed */
+ if (addr == 2)
+ mips_syscall_update_nr(child, regs);
+ else if (addr == 4 &&
+ mips_syscall_is_indirect(child, regs))
+ mips_syscall_update_nr(child, regs);
break;
case FPR_BASE ... FPR_BASE + 31: {
union fpureg *fregs = get_fpu_regs(child);
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/reg.h>
+#include <asm/syscall.h>
#include <linux/uaccess.h>
#include <asm/bootinfo.h>
switch (addr) {
case 0 ... 31:
regs->regs[addr] = data;
+ /* System call number may have been changed */
+ if (addr == 2)
+ mips_syscall_update_nr(child, regs);
+ else if (addr == 4 &&
+ mips_syscall_is_indirect(child, regs))
+ mips_syscall_update_nr(child, regs);
break;
case FPR_BASE ... FPR_BASE + 31: {
union fpureg *fregs = get_fpu_regs(child);