VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / arch / ppc64 / kernel / proc_ppc64.c
1 /*
2  * arch/ppc64/kernel/proc_ppc64.c
3  *
4  * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation
5  * 
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.
10  * 
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.
15  * 
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
19  */
20
21 #include <linux/config.h>
22 #include <linux/init.h>
23 #include <linux/mm.h>
24 #include <linux/proc_fs.h>
25 #include <linux/slab.h>
26 #include <linux/kernel.h>
27
28 #include <asm/naca.h>
29 #include <asm/paca.h>
30 #include <asm/systemcfg.h>
31 #include <asm/rtas.h>
32 #include <asm/uaccess.h>
33 #include <asm/prom.h>
34
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 );
38
39 static struct file_operations page_map_fops = {
40         .llseek = page_map_seek,
41         .read   = page_map_read,
42         .mmap   = page_map_mmap
43 };
44
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 = {
55         .write = ofdt_write
56 };
57 #endif
58
59 /*
60  * NOTE: since paca data is always in flux the values will never be a
61  * consistant set.
62  */
63 static void __init proc_create_paca(struct proc_dir_entry *dir, int num)
64 {
65         struct proc_dir_entry *ent;
66         struct paca_struct *lpaca = paca + num;
67         char buf[16];
68
69         sprintf(buf, "%02x", num);
70         ent = create_proc_entry(buf, S_IRUSR, dir);
71         if (ent) {
72                 ent->nlink = 1;
73                 ent->data = lpaca;
74                 ent->size = 4096;
75                 ent->proc_fops = &page_map_fops;
76         }
77 }
78
79 /*
80  * Create the ppc64 and ppc64/rtas directories early. This allows us to
81  * assume that they have been previously created in drivers.
82  */
83 static int __init proc_ppc64_create(void)
84 {
85         struct proc_dir_entry *root;
86
87         root = proc_mkdir("ppc64", NULL);
88         if (!root)
89                 return 1;
90
91         if (!(systemcfg->platform & PLATFORM_PSERIES))
92                 return 0;
93
94         if (!proc_mkdir("rtas", root))
95                 return 1;
96
97         if (!proc_symlink("rtas", NULL, "ppc64/rtas"))
98                 return 1;
99
100         return 0;
101 }
102 core_initcall(proc_ppc64_create);
103
104 static int __init proc_ppc64_init(void)
105 {
106         unsigned long i;
107         struct proc_dir_entry *pde;
108
109         pde = create_proc_entry("ppc64/naca", S_IRUSR, NULL);
110         if (!pde)
111                 return 1;
112         pde->nlink = 1;
113         pde->data = naca;
114         pde->size = 4096;
115         pde->proc_fops = &page_map_fops;
116
117         pde = create_proc_entry("ppc64/systemcfg", S_IFREG|S_IRUGO, NULL);
118         if (!pde)
119                 return 1;
120         pde->nlink = 1;
121         pde->data = systemcfg;
122         pde->size = 4096;
123         pde->proc_fops = &page_map_fops;
124
125         /* /proc/ppc64/paca/XX -- raw paca contents.  Only readable to root */
126         pde = proc_mkdir("ppc64/paca", NULL);
127         if (!pde)
128                 return 1;
129         for_each_cpu(i)
130                 proc_create_paca(pde, i);
131
132 #ifdef CONFIG_PPC_PSERIES
133         if ((systemcfg->platform & PLATFORM_PSERIES))
134                 proc_ppc64_create_ofdt();
135 #endif
136
137         return 0;
138 }
139 __initcall(proc_ppc64_init);
140
141 static loff_t page_map_seek( struct file *file, loff_t off, int whence)
142 {
143         loff_t new;
144         struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
145
146         switch(whence) {
147         case 0:
148                 new = off;
149                 break;
150         case 1:
151                 new = file->f_pos + off;
152                 break;
153         case 2:
154                 new = dp->size + off;
155                 break;
156         default:
157                 return -EINVAL;
158         }
159         if ( new < 0 || new > dp->size )
160                 return -EINVAL;
161         return (file->f_pos = new);
162 }
163
164 static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
165 {
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);
168 }
169
170 static int page_map_mmap( struct file *file, struct vm_area_struct *vma )
171 {
172         struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
173
174         vma->vm_flags |= VM_SHM | VM_LOCKED;
175
176         if ((vma->vm_end - vma->vm_start) > dp->size)
177                 return -EINVAL;
178
179         remap_page_range( vma, vma->vm_start, __pa(dp->data), dp->size, vma->vm_page_prot );
180         return 0;
181 }
182
183 #ifdef CONFIG_PPC_PSERIES
184 /* create /proc/ppc64/ofdt write-only by root */
185 static void proc_ppc64_create_ofdt(void)
186 {
187         struct proc_dir_entry *ent;
188
189         ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL);
190         if (ent) {
191                 ent->nlink = 1;
192                 ent->data = NULL;
193                 ent->size = 0;
194                 ent->proc_fops = &ofdt_fops;
195         }
196 }
197
198 /**
199  * ofdt_write - perform operations on the Open Firmware device tree
200  *
201  * @file: not used
202  * @buf: command and arguments
203  * @count: size of the command buffer
204  * @off: not used
205  *
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).
209  */
210 static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
211 {
212         int rv = 0;
213         char *kbuf;
214         char *tmp;
215
216         if (!(kbuf = kmalloc(count + 1, GFP_KERNEL))) {
217                 rv = -ENOMEM;
218                 goto out;
219         }
220         if (copy_from_user(kbuf, buf, count)) {
221                 rv = -EFAULT;
222                 goto out;
223         }
224
225         kbuf[count] = '\0';
226
227         tmp = strchr(kbuf, ' ');
228         if (!tmp) {
229                 rv = -EINVAL;
230                 goto out;
231         }
232         *tmp = '\0';
233         tmp++;
234
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);
239         else
240                 rv = -EINVAL;
241 out:
242         kfree(kbuf);
243         return rv ? rv : count;
244 }
245
246 static int do_remove_node(char *buf)
247 {
248         struct device_node *node;
249         int rv = -ENODEV;
250
251         if ((node = of_find_node_by_path(buf)))
252                 rv = of_remove_node(node);
253
254         of_node_put(node);
255         return rv;
256 }
257
258 static int do_add_node(char *buf, size_t bufsize)
259 {
260         char *path, *end, *name;
261         struct device_node *np;
262         struct property *prop = NULL;
263         unsigned char* value;
264         int length, rv = 0;
265
266         end = buf + bufsize;
267         path = buf;
268         buf = strchr(buf, ' ');
269         if (!buf)
270                 return -EINVAL;
271         *buf = '\0';
272         buf++;
273
274         if ((np = of_find_node_by_path(path))) {
275                 of_node_put(np);
276                 return -EINVAL;
277         }
278
279         /* rv = build_prop_list(tmp, bufsize - (tmp - buf), &proplist); */
280         while (buf < end &&
281                (buf = parse_next_property(buf, end, &name, &length, &value))) {
282                 struct property *last = prop;
283
284                 prop = new_property(name, length, value, last);
285                 if (!prop) {
286                         rv = -ENOMEM;
287                         prop = last;
288                         goto out;
289                 }
290         }
291         if (!buf) {
292                 rv = -EINVAL;
293                 goto out;
294         }
295
296         rv = of_add_node(path, prop);
297
298 out:
299         if (rv)
300                 release_prop_list(prop);
301         return rv;
302 }
303
304 static struct property *new_property(const char *name, const int length, const unsigned char *value, struct property *last)
305 {
306         struct property *new = kmalloc(sizeof(*new), GFP_KERNEL);
307
308         if (!new)
309                 return NULL;
310         memset(new, 0, sizeof(*new));
311
312         if (!(new->name = kmalloc(strlen(name) + 1, GFP_KERNEL)))
313                 goto cleanup;
314         if (!(new->value = kmalloc(length + 1, GFP_KERNEL)))
315                 goto cleanup;
316
317         strcpy(new->name, name);
318         memcpy(new->value, value, length);
319         *(((char *)new->value) + length) = 0;
320         new->length = length;
321         new->next = last;
322         return new;
323
324 cleanup:
325         if (new->name)
326                 kfree(new->name);
327         if (new->value)
328                 kfree(new->value);
329         kfree(new);
330         return NULL;
331 }
332
333 /**
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
340  *
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.
344  */
345 static char * parse_next_property(char *buf, char *end, char **name, int *length, unsigned char **value)
346 {
347         char *tmp;
348
349         *name = buf;
350
351         tmp = strchr(buf, ' ');
352         if (!tmp) {
353                 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
354                 return NULL;
355         }
356         *tmp = '\0';
357
358         if (++tmp >= end) {
359                 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
360                 return NULL;
361         }
362
363         /* now we're on the length */
364         *length = -1;
365         *length = simple_strtoul(tmp, &tmp, 10);
366         if (*length == -1) {
367                 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
368                 return NULL;
369         }
370         if (*tmp != ' ' || ++tmp >= end) {
371                 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
372                 return NULL;
373         }
374
375         /* now we're on the value */
376         *value = tmp;
377         tmp += *length;
378         if (tmp > end) {
379                 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
380                 return NULL;
381         }
382         else if (tmp < end && *tmp != ' ' && *tmp != '\0') {
383                 printk(KERN_ERR "property parse failed in %s at line %d\n", __FUNCTION__, __LINE__);
384                 return NULL;
385         }
386         tmp++;
387
388         /* and now we should be on the next name, or the end */
389         return tmp;
390 }
391
392 static void release_prop_list(const struct property *prop)
393 {
394         struct property *next;
395         for (; prop; prop = next) {
396                 next = prop->next;
397                 kfree(prop->name);
398                 kfree(prop->value);
399                 kfree(prop);
400         }
401
402 }
403 #endif  /* defined(CONFIG_PPC_PSERIES) */