at v3.14 5.4 kB view raw
1/* 2 * proc_devtree.c - handles /proc/device-tree 3 * 4 * Copyright 1997 Paul Mackerras 5 */ 6#include <linux/errno.h> 7#include <linux/init.h> 8#include <linux/time.h> 9#include <linux/proc_fs.h> 10#include <linux/seq_file.h> 11#include <linux/printk.h> 12#include <linux/stat.h> 13#include <linux/string.h> 14#include <linux/of.h> 15#include <linux/export.h> 16#include <linux/slab.h> 17#include <asm/uaccess.h> 18#include "internal.h" 19 20static inline void set_node_proc_entry(struct device_node *np, 21 struct proc_dir_entry *de) 22{ 23 np->pde = de; 24} 25 26static struct proc_dir_entry *proc_device_tree; 27 28/* 29 * Supply data on a read from /proc/device-tree/node/property. 30 */ 31static int property_proc_show(struct seq_file *m, void *v) 32{ 33 struct property *pp = m->private; 34 35 seq_write(m, pp->value, pp->length); 36 return 0; 37} 38 39static int property_proc_open(struct inode *inode, struct file *file) 40{ 41 return single_open(file, property_proc_show, __PDE_DATA(inode)); 42} 43 44static const struct file_operations property_proc_fops = { 45 .owner = THIS_MODULE, 46 .open = property_proc_open, 47 .read = seq_read, 48 .llseek = seq_lseek, 49 .release = single_release, 50}; 51 52/* 53 * For a node with a name like "gc@10", we make symlinks called "gc" 54 * and "@10" to it. 55 */ 56 57/* 58 * Add a property to a node 59 */ 60static struct proc_dir_entry * 61__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp, 62 const char *name) 63{ 64 struct proc_dir_entry *ent; 65 66 /* 67 * Unfortunately proc_register puts each new entry 68 * at the beginning of the list. So we rearrange them. 69 */ 70 ent = proc_create_data(name, 71 strncmp(name, "security-", 9) ? S_IRUGO : S_IRUSR, 72 de, &property_proc_fops, pp); 73 if (ent == NULL) 74 return NULL; 75 76 if (!strncmp(name, "security-", 9)) 77 proc_set_size(ent, 0); /* don't leak number of password chars */ 78 else 79 proc_set_size(ent, pp->length); 80 81 return ent; 82} 83 84 85void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop) 86{ 87 __proc_device_tree_add_prop(pde, prop, prop->name); 88} 89 90void proc_device_tree_remove_prop(struct proc_dir_entry *pde, 91 struct property *prop) 92{ 93 remove_proc_entry(prop->name, pde); 94} 95 96void proc_device_tree_update_prop(struct proc_dir_entry *pde, 97 struct property *newprop, 98 struct property *oldprop) 99{ 100 struct proc_dir_entry *ent; 101 102 if (!oldprop) { 103 proc_device_tree_add_prop(pde, newprop); 104 return; 105 } 106 107 for (ent = pde->subdir; ent != NULL; ent = ent->next) 108 if (ent->data == oldprop) 109 break; 110 if (ent == NULL) { 111 pr_warn("device-tree: property \"%s\" does not exist\n", 112 oldprop->name); 113 } else { 114 ent->data = newprop; 115 ent->size = newprop->length; 116 } 117} 118 119/* 120 * Various dodgy firmware might give us nodes and/or properties with 121 * conflicting names. That's generally ok, except for exporting via /proc, 122 * so munge names here to ensure they're unique. 123 */ 124 125static int duplicate_name(struct proc_dir_entry *de, const char *name) 126{ 127 struct proc_dir_entry *ent; 128 int found = 0; 129 130 spin_lock(&proc_subdir_lock); 131 132 for (ent = de->subdir; ent != NULL; ent = ent->next) { 133 if (strcmp(ent->name, name) == 0) { 134 found = 1; 135 break; 136 } 137 } 138 139 spin_unlock(&proc_subdir_lock); 140 141 return found; 142} 143 144static const char *fixup_name(struct device_node *np, struct proc_dir_entry *de, 145 const char *name) 146{ 147 char *fixed_name; 148 int fixup_len = strlen(name) + 2 + 1; /* name + #x + \0 */ 149 int i = 1, size; 150 151realloc: 152 fixed_name = kmalloc(fixup_len, GFP_KERNEL); 153 if (fixed_name == NULL) { 154 pr_err("device-tree: Out of memory trying to fixup " 155 "name \"%s\"\n", name); 156 return name; 157 } 158 159retry: 160 size = snprintf(fixed_name, fixup_len, "%s#%d", name, i); 161 size++; /* account for NULL */ 162 163 if (size > fixup_len) { 164 /* We ran out of space, free and reallocate. */ 165 kfree(fixed_name); 166 fixup_len = size; 167 goto realloc; 168 } 169 170 if (duplicate_name(de, fixed_name)) { 171 /* Multiple duplicates. Retry with a different offset. */ 172 i++; 173 goto retry; 174 } 175 176 pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n", 177 np->full_name, fixed_name); 178 179 return fixed_name; 180} 181 182/* 183 * Process a node, adding entries for its children and its properties. 184 */ 185void proc_device_tree_add_node(struct device_node *np, 186 struct proc_dir_entry *de) 187{ 188 struct property *pp; 189 struct proc_dir_entry *ent; 190 struct device_node *child; 191 const char *p; 192 193 set_node_proc_entry(np, de); 194 for (child = NULL; (child = of_get_next_child(np, child));) { 195 /* Use everything after the last slash, or the full name */ 196 p = kbasename(child->full_name); 197 198 if (duplicate_name(de, p)) 199 p = fixup_name(np, de, p); 200 201 ent = proc_mkdir(p, de); 202 if (ent == NULL) 203 break; 204 proc_device_tree_add_node(child, ent); 205 } 206 of_node_put(child); 207 208 for (pp = np->properties; pp != NULL; pp = pp->next) { 209 p = pp->name; 210 211 if (strchr(p, '/')) 212 continue; 213 214 if (duplicate_name(de, p)) 215 p = fixup_name(np, de, p); 216 217 ent = __proc_device_tree_add_prop(de, pp, p); 218 if (ent == NULL) 219 break; 220 } 221} 222 223/* 224 * Called on initialization to set up the /proc/device-tree subtree 225 */ 226void __init proc_device_tree_init(void) 227{ 228 struct device_node *root; 229 230 proc_device_tree = proc_mkdir("device-tree", NULL); 231 if (proc_device_tree == NULL) 232 return; 233 root = of_find_node_by_path("/"); 234 if (root == NULL) { 235 remove_proc_entry("device-tree", NULL); 236 pr_debug("/proc/device-tree: can't find root\n"); 237 return; 238 } 239 proc_device_tree_add_node(root, proc_device_tree); 240 of_node_put(root); 241}