[ppc64] add rtas syscall, from John Rose

Added RTAS syscall.  Reserved lowmem rtas_rmo_buf for userspace use. 
Created "rmo_buffer" proc file to export bounds of rtas_rmo_buf.


---

 arch/ppc/kernel/misc.S        |    1 +
 arch/ppc64/kernel/misc.S      |    2 ++
 arch/ppc64/kernel/prom.c      |    3 +++
 arch/ppc64/kernel/rtas-proc.c |   34 ++++++++++++++++++++++++++++++++++
 arch/ppc64/kernel/rtas.c      |   39 +++++++++++++++++++++++++++++++++++++++
 arch/ppc64/kernel/syscalls.c  |    4 ++++
 include/asm-ppc/unistd.h      |    3 ++-
 include/asm-ppc64/rtas.h      |    6 ++++++
 include/asm-ppc64/unistd.h    |    4 +++-
 9 files changed, 94 insertions(+), 2 deletions(-)

diff -puN arch/ppc/kernel/misc.S~ppc64-sys_rtas arch/ppc/kernel/misc.S
--- 25/arch/ppc/kernel/misc.S~ppc64-sys_rtas	2004-01-13 23:22:43.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/misc.S	2004-01-13 23:22:43.000000000 -0800
@@ -1385,3 +1385,4 @@ _GLOBAL(sys_call_table)
 	.long sys_statfs64
 	.long sys_fstatfs64
 	.long ppc_fadvise64_64
+	.long sys_ni_syscall	/* 255 - rtas (used on ppc64) */
diff -puN arch/ppc64/kernel/misc.S~ppc64-sys_rtas arch/ppc64/kernel/misc.S
--- 25/arch/ppc64/kernel/misc.S~ppc64-sys_rtas	2004-01-13 23:22:43.000000000 -0800
+++ 25-akpm/arch/ppc64/kernel/misc.S	2004-01-13 23:22:43.000000000 -0800
@@ -853,6 +853,7 @@ _GLOBAL(sys_call_table32)
 	.llong .compat_statfs64
 	.llong .compat_fstatfs64
 	.llong .ppc32_fadvise64_64	/* 32bit only fadvise64_64 */
+	.llong .ppc_rtas		/* 255 */
 
 	.balign 8
 _GLOBAL(sys_call_table)
@@ -1111,3 +1112,4 @@ _GLOBAL(sys_call_table)
 	.llong .sys_statfs64
 	.llong .sys_fstatfs64
 	.llong .sys_ni_syscall		/* 32bit only fadvise64_64 */
+	.llong .ppc_rtas		/* 255 */
diff -puN arch/ppc64/kernel/prom.c~ppc64-sys_rtas arch/ppc64/kernel/prom.c
--- 25/arch/ppc64/kernel/prom.c~ppc64-sys_rtas	2004-01-13 23:22:43.000000000 -0800
+++ 25-akpm/arch/ppc64/kernel/prom.c	2004-01-13 23:22:43.000000000 -0800
@@ -613,6 +613,9 @@ prom_instantiate_rtas(void)
 						      _rtas->base) >= 0) {
 				_rtas->entry = (long)_prom->args.rets[1];
 			}
+			RELOC(rtas_rmo_buf)
+				= lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE,
+							rtas_region);
 		}
 
 		if (_rtas->entry <= 0) {
diff -puN arch/ppc64/kernel/rtas-proc.c~ppc64-sys_rtas arch/ppc64/kernel/rtas-proc.c
--- 25/arch/ppc64/kernel/rtas-proc.c~ppc64-sys_rtas	2004-01-13 23:22:43.000000000 -0800
+++ 25-akpm/arch/ppc64/kernel/rtas-proc.c	2004-01-13 23:22:43.000000000 -0800
@@ -161,6 +161,8 @@ static ssize_t ppc_rtas_tone_volume_writ
 		size_t count, loff_t *ppos);
 static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
 		size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_rmo_buf_read(struct file *file, char *buf,
+				    size_t count, loff_t *ppos);
 
 struct file_operations ppc_rtas_poweron_operations = {
 	.read =		ppc_rtas_poweron_read,
@@ -185,6 +187,10 @@ struct file_operations ppc_rtas_tone_vol
 	.write =	ppc_rtas_tone_volume_write
 };
 
+static struct file_operations ppc_rtas_rmo_buf_ops = {
+	.read =		ppc_rtas_rmo_buf_read,
+};
+
 int ppc_rtas_find_all_sensors (void);
 int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
 		int error, char * buf);
@@ -233,6 +239,9 @@ void proc_rtas_init(void)
 
 	entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas); 
 	if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations;
+
+	entry = create_proc_entry("rmo_buffer", S_IRUSR, proc_rtas);
+	if (entry) entry->proc_fops = &ppc_rtas_rmo_buf_ops;
 }
 
 /* ****************************************************************** */
@@ -919,3 +928,28 @@ static ssize_t ppc_rtas_tone_volume_read
 	*ppos += n;
 	return n;
 }
+
+#define RMO_READ_BUF_MAX 30
+
+/* RTAS Userspace access */
+static ssize_t ppc_rtas_rmo_buf_read(struct file *file, char __user *buf,
+				    size_t count, loff_t *ppos)
+{
+	char kbuf[RMO_READ_BUF_MAX];
+	int n;
+
+	n = sprintf(kbuf, "%016lx %x\n", rtas_rmo_buf, RTAS_RMOBUF_MAX);
+	if (n > count)
+		n = count;
+
+	if (ppos && *ppos != 0)
+		return 0;
+
+	if (copy_to_user(buf, kbuf, n))
+		return -EFAULT;
+
+	if (ppos)
+		*ppos = n;
+	
+	return n;
+}
diff -puN arch/ppc64/kernel/rtas.c~ppc64-sys_rtas arch/ppc64/kernel/rtas.c
--- 25/arch/ppc64/kernel/rtas.c~ppc64-sys_rtas	2004-01-13 23:22:43.000000000 -0800
+++ 25-akpm/arch/ppc64/kernel/rtas.c	2004-01-13 23:22:43.000000000 -0800
@@ -29,6 +29,7 @@
 #include <asm/abs_addr.h>
 #include <asm/udbg.h>
 #include <asm/delay.h>
+#include <asm/uaccess.h>
 
 struct flash_block_list_header rtas_firmware_flash_list = {0, 0};
 
@@ -383,6 +384,44 @@ rtas_halt(void)
         rtas_power_off();
 }
 
+unsigned long rtas_rmo_buf = 0;
+
+asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
+{
+	struct rtas_args args;
+	unsigned long flags;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0)
+		return -EFAULT;
+
+	if (args.nargs > ARRAY_SIZE(args.args)
+	    || args.nret > ARRAY_SIZE(args.args)
+	    || args.nargs + args.nret > ARRAY_SIZE(args.args))
+		return -EINVAL;
+
+	/* Copy in args. */
+	if (copy_from_user(args.args, uargs->args,
+			   args.nargs * sizeof(rtas_arg_t)) != 0)
+		return -EFAULT;
+
+	spin_lock_irqsave(&rtas.lock, flags);
+	get_paca()->xRtas = args;
+	enter_rtas((void *)__pa((unsigned long)&get_paca()->xRtas));
+	args = get_paca()->xRtas;
+	spin_unlock_irqrestore(&rtas.lock, flags);
+
+	/* Copy out args. */
+	if (copy_to_user(uargs->args + args.nargs,
+			 args.args + args.nargs,
+			 args.nret * sizeof(rtas_arg_t)) != 0)
+		return -EFAULT;
+
+	return 0;
+}
+
 EXPORT_SYMBOL(proc_ppc64);
 EXPORT_SYMBOL(rtas_firmware_flash_list);
 EXPORT_SYMBOL(rtas_token);
diff -puN arch/ppc64/kernel/syscalls.c~ppc64-sys_rtas arch/ppc64/kernel/syscalls.c
--- 25/arch/ppc64/kernel/syscalls.c~ppc64-sys_rtas	2004-01-13 23:22:43.000000000 -0800
+++ 25-akpm/arch/ppc64/kernel/syscalls.c	2004-01-13 23:22:43.000000000 -0800
@@ -41,6 +41,7 @@
 #include <asm/ipc.h>
 #include <asm/semaphore.h>
 #include <asm/time.h>
+#include <asm/unistd.h>
 
 extern unsigned long wall_jiffies;
 
@@ -234,3 +235,6 @@ asmlinkage time_t sys64_time(time_t* tlo
 
 	return secs;
 }
+
+/* Only exists on P-series. */
+cond_syscall(ppc_rtas);
diff -puN include/asm-ppc/unistd.h~ppc64-sys_rtas include/asm-ppc/unistd.h
--- 25/include/asm-ppc/unistd.h~ppc64-sys_rtas	2004-01-13 23:22:43.000000000 -0800
+++ 25-akpm/include/asm-ppc/unistd.h	2004-01-13 23:22:43.000000000 -0800
@@ -259,8 +259,9 @@
 #define __NR_statfs64		252
 #define __NR_fstatfs64		253
 #define __NR_fadvise64_64	254
+#define __NR_rtas		255
 
-#define __NR_syscalls		255
+#define __NR_syscalls		256
 
 #define __NR(n)	#n
 
diff -puN include/asm-ppc64/rtas.h~ppc64-sys_rtas include/asm-ppc64/rtas.h
--- 25/include/asm-ppc64/rtas.h~ppc64-sys_rtas	2004-01-13 23:22:43.000000000 -0800
+++ 25-akpm/include/asm-ppc64/rtas.h	2004-01-13 23:22:43.000000000 -0800
@@ -19,6 +19,9 @@
 #define RTAS_UNKNOWN_SERVICE (-1)
 #define RTAS_INSTANTIATE_MAX (1UL<<30) /* Don't instantiate rtas at/above this value */
 
+/* Buffer size for ppc_rtas system call. */
+#define RTAS_RMOBUF_MAX (64 * 1024)
+
 /*
  * In general to call RTAS use rtas_token("string") to lookup
  * an RTAS token for the given string (e.g. "event-scan").
@@ -189,4 +192,7 @@ static inline int rtas_is_extended_busy(
 extern spinlock_t rtas_data_buf_lock;
 extern char rtas_data_buf[RTAS_DATA_BUF_SIZE];
 
+/* RMO buffer reserved for user-space RTAS use */
+extern unsigned long rtas_rmo_buf;
+
 #endif /* _PPC64_RTAS_H */
diff -puN include/asm-ppc64/unistd.h~ppc64-sys_rtas include/asm-ppc64/unistd.h
--- 25/include/asm-ppc64/unistd.h~ppc64-sys_rtas	2004-01-13 23:22:43.000000000 -0800
+++ 25-akpm/include/asm-ppc64/unistd.h	2004-01-13 23:22:43.000000000 -0800
@@ -264,8 +264,10 @@
 #define __NR_utimes		251
 #define __NR_statfs64		252
 #define __NR_fstatfs64		253
+#define __NR_fadvise64_64	254
+#define __NR_rtas		255
 
-#define __NR_syscalls		254
+#define __NR_syscalls		256
 #ifdef __KERNEL__
 #define NR_syscalls	__NR_syscalls
 #endif

_