2 * arch/ppc64/kernel/proc_ppc64.c
4 * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <linux/config.h>
22 #include <linux/init.h>
24 #include <linux/proc_fs.h>
25 #include <linux/slab.h>
26 #include <linux/kernel.h>
30 #include <asm/systemcfg.h>
32 #include <asm/uaccess.h>
35 static loff_t page_map_seek( struct file *file, loff_t off, int whence);
36 static ssize_t page_map_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos);
37 static int page_map_mmap( struct file *file, struct vm_area_struct *vma );
39 static struct file_operations page_map_fops = {
40 .llseek = page_map_seek,
41 .read = page_map_read,
45 #ifdef CONFIG_PPC_PSERIES
46 /* routines for /proc/ppc64/ofdt */
47 static ssize_t ofdt_write(struct file *, const char __user *, size_t, loff_t *);
48 static void proc_ppc64_create_ofdt(void);
49 static int do_remove_node(char *);
50 static int do_add_node(char *, size_t);
51 static void release_prop_list(const struct property *);
52 static struct property *new_property(const char *, const int, const unsigned char *, struct property *);
53 static char * parse_next_property(char *, char *, char **, int *, unsigned char**);
54 static struct file_operations ofdt_fops = {
60 * NOTE: since paca data is always in flux the values will never be a
63 static void __init proc_create_paca(struct proc_dir_entry *dir, int num)
65 struct proc_dir_entry *ent;
66 struct paca_struct *lpaca = paca + num;
69 sprintf(buf, "%02x", num);
70 ent = create_proc_entry(buf, S_IRUSR, dir);
75 ent->proc_fops = &page_map_fops;
80 * Create the ppc64 and ppc64/rtas directories early. This allows us to
81 * assume that they have been previously created in drivers.
83 static int __init proc_ppc64_create(void)
85 struct proc_dir_entry *root;
87 root = proc_mkdir("ppc64", NULL);
91 if (!(systemcfg->platform & PLATFORM_PSERIES))
94 if (!proc_mkdir("rtas", root))
97 if (!proc_symlink("rtas", NULL, "ppc64/rtas"))
102 core_initcall(proc_ppc64_create);
104 static int __init proc_ppc64_init(void)
107 struct proc_dir_entry *pde;
109 pde = create_proc_entry("ppc64/naca", S_IRUSR, NULL);
115 pde->proc_fops = &page_map_fops;
117 pde = create_proc_entry("ppc64/systemcfg", S_IFREG|S_IRUGO, NULL);
121 pde->data = systemcfg;
123 pde->proc_fops = &page_map_fops;
125 /* /proc/ppc64/paca/XX -- raw paca contents. Only readable to root */
126 pde = proc_mkdir("ppc64/paca", NULL);
130 proc_create_paca(pde, i);
132 #ifdef CONFIG_PPC_PSERIES
133 if ((systemcfg->platform & PLATFORM_PSERIES))
134 proc_ppc64_create_ofdt();
139 __initcall(proc_ppc64_init);
141 static loff_t page_map_seek( struct file *file, loff_t off, int whence)
144 struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
151 new = file->f_pos + off;
154 new = dp->size + off;
159 if ( new < 0 || new > dp->size )
161 return (file->f_pos = new);
164 static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
166 struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
167 return simple_read_from_buffer(buf, nbytes, ppos, dp->data, dp->size);
170 static int page_map_mmap( struct file *file, struct vm_area_struct *vma )
172 struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
174 vma->vm_flags |= VM_SHM | VM_LOCKED;
176 if ((vma->vm_end - vma->vm_start) > dp->size)
179 remap_page_range( vma, vma->vm_start, __pa(dp->data), dp->size, vma->vm_page_prot );
183 #ifdef CONFIG_PPC_PSERIES
184 /* create /proc/ppc64/ofdt write-only by root */
185 static void proc_ppc64_create_ofdt(void)
187 struct proc_dir_entry *ent;
189 ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL);
194 ent->proc_fops = &ofdt_fops;
199 * ofdt_write - perform operations on the Open Firmware device tree
202 * @buf: command and arguments
203 * @count: size of the command buffer
206 * Operations supported at this time are addition and removal of
207 * whole nodes along with their properties. Operations on individual
208 * properties are not implemented (yet).
210 static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
216 if (!(kbuf = kmalloc(count + 1, GFP_KERNEL))) {
220 if (copy_from_user(kbuf, buf, count)) {
227 tmp = strchr(kbuf, ' ');
235 if (!strcmp(kbuf, "add_node"))
236 rv = do_add_node(tmp, count - (tmp - kbuf));
237 else if (!strcmp(kbuf, "remove_node"))
238 rv = do_remove_node(tmp);
243 return rv ? rv : count;
246 static int do_remove_node(char *buf)
248 struct device_node *node;
251 if ((node = of_find_node_by_path(buf)))
252 rv = of_remove_node(node);
258 static int do_add_node(char *buf, size_t bufsize)
260 char *path, *end, *name;
261 struct device_node *np;
262 struct property *prop = NULL;
263 unsigned char* value;
268 buf = strchr(buf, ' ');
274 if ((np = of_find_node_by_path(path))) {
279 /* rv = build_prop_list(tmp, bufsize - (tmp - buf), &proplist); */
281 (buf = parse_next_property(buf, end, &name, &length, &value))) {
282 struct property *last = prop;
284 prop = new_property(name, length, value, last);
296 rv = of_add_node(path, prop);
300 release_prop_list(prop);
304 static struct property *new_property(const char *name, const int length, const unsigned char *value, struct property *last)
306 struct property *new = kmalloc(sizeof(*new), GFP_KERNEL);
310 memset(new, 0, sizeof(*new));
312 if (!(new->name = kmalloc(strlen(name) + 1, GFP_KERNEL)))
314 if (!(new->value = kmalloc(length + 1, GFP_KERNEL)))
317 strcpy(new->name, name);
318 memcpy(new->value, value, length);
319 *(((char *)new->value) + length) = 0;
320 new->length = length;
334 * parse_next_property - process the next property from raw input buffer
335 * @buf: input buffer, must be nul-terminated
336 * @end: end of the input buffer + 1, for validation
337 * @name: return value; set to property name in buf
338 * @length: return value; set to length of value
339 * @value: return value; set to the property value in buf
341 * Note that the caller must make copies of the name and value returned,
342 * this function does no allocation or copying of the data. Return value
343 * is set to the next name in buf, or NULL on error.
345 static char * parse_next_property(char *buf, char *end, char **name, int *length, unsigned char **value)
351 tmp = strchr(buf, ' ');
353 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
359 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
363 /* now we're on the length */
365 *length = simple_strtoul(tmp, &tmp, 10);
367 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
370 if (*tmp != ' ' || ++tmp >= end) {
371 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
375 /* now we're on the value */
379 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
382 else if (tmp < end && *tmp != ' ' && *tmp != '\0') {
383 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
388 /* and now we should be on the next name, or the end */
392 static void release_prop_list(const struct property *prop)
394 struct property *next;
395 for (; prop; prop = next) {
403 #endif /* defined(CONFIG_PPC_PSERIES) */