This implements sys_indirect for 32-bit and 64-bit powerpc machines,
including a 32-bit compatibility implementation for 64-bit powerpc.
I decided to use assembly language for call_syscall because on 64-bit
powerpc the system call table has the addresses of the function text
rather than pointers to function descriptors; hence the system call
functions can't be called from C via the system call table.
Signed-off-by: Paul Mackerras <[EMAIL PROTECTED]>
---
This patch applies on top of Ulrich Drepper's series adding the
generic and x86-specific code for sys_indirect.
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 69a91bd..fd6781c 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -461,6 +461,25 @@ ppc_swapcontext:
b sys_swapcontext
/*
+ * long call_compat_syscall(struct indirect_registers32 *regs)
+ * This function assumes that regs->syscall_nr has already been validated.
+ */
+_GLOBAL(call_syscall)
+ lwz r0,0(r3)/* system call number */
+ lis r11,[EMAIL PROTECTED]
+ addir11,r11,[EMAIL PROTECTED]
+ slwir0,r0,2
+ lwzxr10,r11,r0
+ mtctr r10
+ lwz r4,8(r3)
+ lwz r5,12(r3)
+ lwz r6,16(r3)
+ lwz r7,20(r3)
+ lwz r8,24(r3)
+ lwz r3,4(r3)
+ bctr
+
+/*
* Top-level page fault handling.
* This is in assembler because if do_page_fault tells us that
* it is a bad kernel page fault, we want to save the non-volatile
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 148a354..516ee70 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -315,6 +315,43 @@ _GLOBAL(ret_from_fork)
b syscall_exit
/*
+ * long call_syscall(struct indirect_registers *regs)
+ * This function assumes that regs->syscall_nr has already been validated.
+ */
+_GLOBAL(call_syscall)
+ ld r11,[EMAIL PROTECTED](2)
+ ld r0,0(r3)/* system call number */
+ sldir0,r0,4
+ ldx r10,r11,r0
+ mtctr r10
+ ld r4,16(r3)
+ ld r5,24(r3)
+ ld r6,32(r3)
+ ld r7,40(r3)
+ ld r8,48(r3)
+ ld r3,8(r3)
+ bctr
+
+/*
+ * long call_compat_syscall(struct indirect_registers32 *regs)
+ * This function assumes that regs->syscall_nr has already been validated.
+ */
+_GLOBAL(call_compat_syscall)
+ ld r11,[EMAIL PROTECTED](2)
+ lwz r0,0(r3)/* system call number */
+ sldir0,r0,4
+ addir11,r11,8
+ ldx r10,r11,r0
+ mtctr r10
+ lwz r4,8(r3)
+ lwz r5,12(r3)
+ lwz r6,16(r3)
+ lwz r7,20(r3)
+ lwz r8,24(r3)
+ lwz r3,4(r3)
+ bctr
+
+/*
* This routine switches between two different tasks. The process
* state of one is saved on its kernel stack. Then the state
* of the other is restored from its kernel stack. The memory
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index 4a4f5c6..fcaf0b2 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -826,3 +826,37 @@ asmlinkage long compat_sys_sync_file_range2(int fd,
unsigned int flags,
return sys_sync_file_range(fd, offset, nbytes, flags);
}
+
+long compat_sys_indirect(struct indirect_registers32 __user *userregs,
+void __user *userparams, size_t paramslen,
+int flags)
+{
+ struct indirect_registers32 regs;
+ long result;
+
+ if (unlikely(flags != 0))
+ return -EINVAL;
+
+ if (copy_from_user(®s, userregs, sizeof(regs)))
+ return -EFAULT;
+
+ switch (regs.syscall_nr) {
+#define INDSYSCALL(name) __NR_##name
+#include
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (paramslen > sizeof(union indirect_params))
+ return -EINVAL;
+
+ result = -EFAULT;
+ if (!copy_from_user(¤t->indirect_params, userparams, paramslen))
+ result = call_compat_syscall(®s);
+
+ memset(¤t->indirect_params, '\0', paramslen);
+
+ return result;
+}
diff --git a/include/asm-powerpc/indirect.h b/include/asm-powerpc/indirect.h
new file mode 100644
index 000..fcc6729
--- /dev/null
+++ b/include/asm-powerpc/indirect.h
@@ -0,0 +1,32 @@
+#ifndef _ASM_POWERPC_INDIRECT_H_
+#define _ASM_POWERPC_INDIRECT_H_
+/*
+ * Copyright 2007 Paul Mackerras <[EMAIL PROTECTED]>, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+struct indirect_registers {
+ unsigned long syscall_nr;
+ unsigned long args[6];
+};
+
+extern lon