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", 0);
91 if (!(systemcfg->platform & PLATFORM_PSERIES))
94 if (!proc_mkdir("rtas", root))
97 if (!proc_symlink("rtas", 0, "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 *buf, size_t nbytes, loff_t *ppos)
166 unsigned pos = *ppos;
167 struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
169 if ( pos >= dp->size )
171 if ( nbytes >= dp->size )
173 if ( pos + nbytes > dp->size )
174 nbytes = dp->size - pos;
176 copy_to_user( buf, (char *)dp->data + pos, nbytes );
177 *ppos = pos + nbytes;
181 static int page_map_mmap( struct file *file, struct vm_area_struct *vma )
183 struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
185 vma->vm_flags |= VM_SHM | VM_LOCKED;
187 if ((vma->vm_end - vma->vm_start) > dp->size)
190 remap_page_range( vma, vma->vm_start, __pa(dp->data), dp->size, vma->vm_page_prot );
194 #ifdef CONFIG_PPC_PSERIES
195 /* create /proc/ppc64/ofdt write-only by root */
196 static void proc_ppc64_create_ofdt(void)
198 struct proc_dir_entry *ent;
200 ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL);
205 ent->proc_fops = &ofdt_fops;
210 * ofdt_write - perform operations on the Open Firmware device tree
213 * @buf: command and arguments
214 * @count: size of the command buffer
217 * Operations supported at this time are addition and removal of
218 * whole nodes along with their properties. Operations on individual
219 * properties are not implemented (yet).
221 static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
227 if (!(kbuf = kmalloc(count + 1, GFP_KERNEL))) {
231 if (copy_from_user(kbuf, buf, count)) {
238 tmp = strchr(kbuf, ' ');
246 if (!strcmp(kbuf, "add_node"))
247 rv = do_add_node(tmp, count - (tmp - kbuf));
248 else if (!strcmp(kbuf, "remove_node"))
249 rv = do_remove_node(tmp);
254 return rv ? rv : count;
257 static int do_remove_node(char *buf)
259 struct device_node *node;
262 if ((node = of_find_node_by_path(buf)))
263 rv = of_remove_node(node);
269 static int do_add_node(char *buf, size_t bufsize)
271 char *path, *end, *name;
272 struct device_node *np;
273 struct property *prop = NULL;
274 unsigned char* value;
279 buf = strchr(buf, ' ');
285 if ((np = of_find_node_by_path(path))) {
290 /* rv = build_prop_list(tmp, bufsize - (tmp - buf), &proplist); */
292 (buf = parse_next_property(buf, end, &name, &length, &value))) {
293 struct property *last = prop;
295 prop = new_property(name, length, value, last);
307 rv = of_add_node(path, prop);
311 release_prop_list(prop);
315 static struct property *new_property(const char *name, const int length, const unsigned char *value, struct property *last)
317 struct property *new = kmalloc(sizeof(*new), GFP_KERNEL);
321 memset(new, 0, sizeof(*new));
323 if (!(new->name = kmalloc(strlen(name) + 1, GFP_KERNEL)))
325 if (!(new->value = kmalloc(length + 1, GFP_KERNEL)))
328 strcpy(new->name, name);
329 memcpy(new->value, value, length);
330 *(((char *)new->value) + length) = 0;
331 new->length = length;
345 * parse_next_property - process the next property from raw input buffer
346 * @buf: input buffer, must be nul-terminated
347 * @end: end of the input buffer + 1, for validation
348 * @name: return value; set to property name in buf
349 * @length: return value; set to length of value
350 * @value: return value; set to the property value in buf
352 * Note that the caller must make copies of the name and value returned,
353 * this function does no allocation or copying of the data. Return value
354 * is set to the next name in buf, or NULL on error.
356 static char * parse_next_property(char *buf, char *end, char **name, int *length, unsigned char **value)
362 tmp = strchr(buf, ' ');
364 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
370 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
374 /* now we're on the length */
376 *length = simple_strtoul(tmp, &tmp, 10);
378 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
381 if (*tmp != ' ' || ++tmp >= end) {
382 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
386 /* now we're on the value */
390 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
393 else if (tmp < end && *tmp != ' ' && *tmp != '\0') {
394 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
399 /* and now we should be on the next name, or the end */
403 static void release_prop_list(const struct property *prop)
405 struct property *next;
406 for (; prop; prop = next) {
414 #endif /* defined(CONFIG_PPC_PSERIES) */