[PATCH] RTAS syscall - review request
John Rose
johnrose at austin.ibm.com
Tue Nov 11 04:51:21 EST 2003
This patch implements a generic RTAS interface to userspace through a
system call. It was originally written by Rusty Russel and modified by
myself. There are two main parts:
- A new "rtas" syscall, which allows a user app to make any RTAS call
available to the system.
- A special RMO buffer is reserved at boot time for user-space apps that
require low memory. Some RTAS calls require such "workarea" buffers,
so the kernel needs to somehow export low memory regions for
user-space use. This implementation exports the physical address
and size of the reserved region through a simple /proc file. The user
app is then free to mmap() /dev/mem at the address specified.
Please respond with any comments by EOB Thursday, Nov 13th.
Thanks-
John
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S Mon Nov 10 11:34:58 2003
+++ b/arch/ppc/kernel/misc.S Mon Nov 10 11:34:58 2003
@@ -1385,3 +1385,4 @@
.long sys_statfs64
.long sys_fstatfs64
.long ppc_fadvise64_64
+ .long sys_ni_syscall /* 255 - rtas (used on ppc64) */
diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
--- a/arch/ppc64/kernel/misc.S Mon Nov 10 11:34:58 2003
+++ b/arch/ppc64/kernel/misc.S Mon Nov 10 11:34:58 2003
@@ -852,6 +852,8 @@
.llong .sys32_utimes
.llong .sys_statfs64
.llong .sys_fstatfs64
+ .llong .sys_ni_syscall /* 32bit only fadvise64 */
+ .llong .ppc_rtas /* 255 */
.balign 8
_GLOBAL(sys_call_table)
@@ -1109,3 +1111,5 @@
.llong .sys_utimes
.llong .sys_statfs64
.llong .sys_fstatfs64
+ .llong .sys_ni_syscall /* 32bit only fadvise64 */
+ .llong .ppc_rtas /* 255 */
diff -Nru a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
--- a/arch/ppc64/kernel/prom.c Mon Nov 10 11:34:58 2003
+++ b/arch/ppc64/kernel/prom.c Mon Nov 10 11:34:58 2003
@@ -611,6 +611,10 @@
_rtas->base) >= 0) {
_rtas->entry = (long)_prom->args.rets[1];
}
+ RELOC(rtas_rmo_buf)
+ = (void *)lmb_alloc_base(RTAS_SYSCALL_MAX,
+ PAGE_SIZE,
+ rtas_region);
}
if (_rtas->entry <= 0) {
diff -Nru a/arch/ppc64/kernel/rtas-proc.c b/arch/ppc64/kernel/rtas-proc.c
--- a/arch/ppc64/kernel/rtas-proc.c Mon Nov 10 11:34:58 2003
+++ b/arch/ppc64/kernel/rtas-proc.c Mon Nov 10 11:34:58 2003
@@ -161,6 +161,8 @@
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 @@
.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 @@
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;
}
/* ****************************************************************** */
@@ -842,6 +851,23 @@
int n;
n = sprintf(buf, "%lu\n", rtas_tone_volume);
+ if (*ppos >= strlen(buf))
+ return 0;
+ if (n > strlen(buf) - *ppos)
+ n = strlen(buf) - *ppos;
+ if (n > count)
+ n = count;
+ *ppos += n;
+ return n;
+}
+
+/* RTAS Userspace access */
+static ssize_t ppc_rtas_rmo_buf_read(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
+{
+ int n;
+
+ n = sprintf(buf, "%p %x\n", rtas_rmo_buf, RTAS_SYSCALL_MAX);
if (*ppos >= strlen(buf))
return 0;
if (n > strlen(buf) - *ppos)
diff -Nru a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c
--- a/arch/ppc64/kernel/rtas.c Mon Nov 10 11:34:58 2003
+++ b/arch/ppc64/kernel/rtas.c Mon Nov 10 11:34:58 2003
@@ -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};
@@ -381,6 +382,44 @@
if (rtas_firmware_flash_list.next)
rtas_flash_bypass_warning();
rtas_power_off();
+}
+
+void *rtas_rmo_buf = NULL;
+
+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);
diff -Nru a/arch/ppc64/kernel/syscalls.c b/arch/ppc64/kernel/syscalls.c
--- a/arch/ppc64/kernel/syscalls.c Mon Nov 10 11:34:58 2003
+++ b/arch/ppc64/kernel/syscalls.c Mon Nov 10 11:34:58 2003
@@ -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 @@
return secs;
}
+
+/* Only exists on P-series. */
+cond_syscall(ppc_rtas);
diff -Nru a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
--- a/include/asm-ppc/unistd.h Mon Nov 10 11:34:58 2003
+++ b/include/asm-ppc/unistd.h Mon Nov 10 11:34:58 2003
@@ -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 -Nru a/include/asm-ppc64/rtas.h b/include/asm-ppc64/rtas.h
--- a/include/asm-ppc64/rtas.h Mon Nov 10 11:34:58 2003
+++ b/include/asm-ppc64/rtas.h Mon Nov 10 11:34:58 2003
@@ -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_SYSCALL_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").
@@ -188,5 +191,8 @@
extern spinlock_t rtas_data_buf_lock;
extern char rtas_data_buf[RTAS_DATA_BUF_SIZE];
+
+/* Buffer used for ppc_rtas system call */
+extern void *rtas_rmo_buf;
#endif /* _PPC64_RTAS_H */
diff -Nru a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h
--- a/include/asm-ppc64/unistd.h Mon Nov 10 11:34:58 2003
+++ b/include/asm-ppc64/unistd.h Mon Nov 10 11:34:58 2003
@@ -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
** Sent via the linuxppc64-dev mail list. See http://lists.linuxppc.org/
More information about the Linuxppc64-dev
mailing list