1 /* 2 * Architecture specific sysfs attributes in /sys/kernel 3 * 4 * Copyright (C) 2007, Intel Corp. 5 * Huang Ying <ying.huang@intel.com> 6 * Copyright (C) 2013, 2013 Red Hat, Inc. 7 * Dave Young <dyoung@redhat.com> 8 * 9 * This file is released under the GPLv2 10 */ 11 12 #include <linux/kobject.h> 13 #include <linux/string.h> 14 #include <linux/sysfs.h> 15 #include <linux/init.h> 16 #include <linux/stat.h> 17 #include <linux/slab.h> 18 #include <linux/mm.h> 19 #include <linux/io.h> 20 21 #include <asm/setup.h> 22 23 static ssize_t version_show(struct kobject *kobj, 24 struct kobj_attribute *attr, char *buf) 25 { 26 return sprintf(buf, "0x%04x\n", boot_params.hdr.version); 27 } 28 29 static struct kobj_attribute boot_params_version_attr = __ATTR_RO(version); 30 31 static ssize_t boot_params_data_read(struct file *fp, struct kobject *kobj, 32 struct bin_attribute *bin_attr, 33 char *buf, loff_t off, size_t count) 34 { 35 memcpy(buf, (void *)&boot_params + off, count); 36 return count; 37 } 38 39 static struct bin_attribute boot_params_data_attr = { 40 .attr = { 41 .name = "data", 42 .mode = S_IRUGO, 43 }, 44 .read = boot_params_data_read, 45 .size = sizeof(boot_params), 46 }; 47 48 static struct attribute *boot_params_version_attrs[] = { 49 &boot_params_version_attr.attr, 50 NULL, 51 }; 52 53 static struct bin_attribute *boot_params_data_attrs[] = { 54 &boot_params_data_attr, 55 NULL, 56 }; 57 58 static const struct attribute_group boot_params_attr_group = { 59 .attrs = boot_params_version_attrs, 60 .bin_attrs = boot_params_data_attrs, 61 }; 62 63 static int kobj_to_setup_data_nr(struct kobject *kobj, int *nr) 64 { 65 const char *name; 66 67 name = kobject_name(kobj); 68 return kstrtoint(name, 10, nr); 69 } 70 71 static int get_setup_data_paddr(int nr, u64 *paddr) 72 { 73 int i = 0; 74 struct setup_data *data; 75 u64 pa_data = boot_params.hdr.setup_data; 76 77 while (pa_data) { 78 if (nr == i) { 79 *paddr = pa_data; 80 return 0; 81 } 82 data = memremap(pa_data, sizeof(*data), MEMREMAP_WB); 83 if (!data) 84 return -ENOMEM; 85 86 pa_data = data->next; 87 memunmap(data); 88 i++; 89 } 90 return -EINVAL; 91 } 92 93 static int __init get_setup_data_size(int nr, size_t *size) 94 { 95 int i = 0; 96 struct setup_data *data; 97 u64 pa_data = boot_params.hdr.setup_data; 98 99 while (pa_data) { 100 data = memremap(pa_data, sizeof(*data), MEMREMAP_WB); 101 if (!data) 102 return -ENOMEM; 103 if (nr == i) { 104 *size = data->len; 105 memunmap(data); 106 return 0; 107 } 108 109 pa_data = data->next; 110 memunmap(data); 111 i++; 112 } 113 return -EINVAL; 114 } 115 116 static ssize_t type_show(struct kobject *kobj, 117 struct kobj_attribute *attr, char *buf) 118 { 119 int nr, ret; 120 u64 paddr; 121 struct setup_data *data; 122 123 ret = kobj_to_setup_data_nr(kobj, &nr); 124 if (ret) 125 return ret; 126 127 ret = get_setup_data_paddr(nr, &paddr); 128 if (ret) 129 return ret; 130 data = memremap(paddr, sizeof(*data), MEMREMAP_WB); 131 if (!data) 132 return -ENOMEM; 133 134 ret = sprintf(buf, "0x%x\n", data->type); 135 memunmap(data); 136 return ret; 137 } 138 139 static ssize_t setup_data_data_read(struct file *fp, 140 struct kobject *kobj, 141 struct bin_attribute *bin_attr, 142 char *buf, 143 loff_t off, size_t count) 144 { 145 int nr, ret = 0; 146 u64 paddr; 147 struct setup_data *data; 148 void *p; 149 150 ret = kobj_to_setup_data_nr(kobj, &nr); 151 if (ret) 152 return ret; 153 154 ret = get_setup_data_paddr(nr, &paddr); 155 if (ret) 156 return ret; 157 data = memremap(paddr, sizeof(*data), MEMREMAP_WB); 158 if (!data) 159 return -ENOMEM; 160 161 if (off > data->len) { 162 ret = -EINVAL; 163 goto out; 164 } 165 166 if (count > data->len - off) 167 count = data->len - off; 168 169 if (!count) 170 goto out; 171 172 ret = count; 173 p = memremap(paddr + sizeof(*data), data->len, MEMREMAP_WB); 174 if (!p) { 175 ret = -ENOMEM; 176 goto out; 177 } 178 memcpy(buf, p + off, count); 179 memunmap(p); 180 out: 181 memunmap(data); 182 return ret; 183 } 184 185 static struct kobj_attribute type_attr = __ATTR_RO(type); 186 187 static struct bin_attribute data_attr __ro_after_init = { 188 .attr = { 189 .name = "data", 190 .mode = S_IRUGO, 191 }, 192 .read = setup_data_data_read, 193 }; 194 195 static struct attribute *setup_data_type_attrs[] = { 196 &type_attr.attr, 197 NULL, 198 }; 199 200 static struct bin_attribute *setup_data_data_attrs[] = { 201 &data_attr, 202 NULL, 203 }; 204 205 static const struct attribute_group setup_data_attr_group = { 206 .attrs = setup_data_type_attrs, 207 .bin_attrs = setup_data_data_attrs, 208 }; 209 210 static int __init create_setup_data_node(struct kobject *parent, 211 struct kobject **kobjp, int nr) 212 { 213 int ret = 0; 214 size_t size; 215 struct kobject *kobj; 216 char name[16]; /* should be enough for setup_data nodes numbers */ 217 snprintf(name, 16, "%d", nr); 218 219 kobj = kobject_create_and_add(name, parent); 220 if (!kobj) 221 return -ENOMEM; 222 223 ret = get_setup_data_size(nr, &size); 224 if (ret) 225 goto out_kobj; 226 227 data_attr.size = size; 228 ret = sysfs_create_group(kobj, &setup_data_attr_group); 229 if (ret) 230 goto out_kobj; 231 *kobjp = kobj; 232 233 return 0; 234 out_kobj: 235 kobject_put(kobj); 236 return ret; 237 } 238 239 static void __init cleanup_setup_data_node(struct kobject *kobj) 240 { 241 sysfs_remove_group(kobj, &setup_data_attr_group); 242 kobject_put(kobj); 243 } 244 245 static int __init get_setup_data_total_num(u64 pa_data, int *nr) 246 { 247 int ret = 0; 248 struct setup_data *data; 249 250 *nr = 0; 251 while (pa_data) { 252 *nr += 1; 253 data = memremap(pa_data, sizeof(*data), MEMREMAP_WB); 254 if (!data) { 255 ret = -ENOMEM; 256 goto out; 257 } 258 pa_data = data->next; 259 memunmap(data); 260 } 261 262 out: 263 return ret; 264 } 265 266 static int __init create_setup_data_nodes(struct kobject *parent) 267 { 268 struct kobject *setup_data_kobj, **kobjp; 269 u64 pa_data; 270 int i, j, nr, ret = 0; 271 272 pa_data = boot_params.hdr.setup_data; 273 if (!pa_data) 274 return 0; 275 276 setup_data_kobj = kobject_create_and_add("setup_data", parent); 277 if (!setup_data_kobj) { 278 ret = -ENOMEM; 279 goto out; 280 } 281 282 ret = get_setup_data_total_num(pa_data, &nr); 283 if (ret) 284 goto out_setup_data_kobj; 285 286 kobjp = kmalloc(sizeof(*kobjp) * nr, GFP_KERNEL); 287 if (!kobjp) { 288 ret = -ENOMEM; 289 goto out_setup_data_kobj; 290 } 291 292 for (i = 0; i < nr; i++) { 293 ret = create_setup_data_node(setup_data_kobj, kobjp + i, i); 294 if (ret) 295 goto out_clean_nodes; 296 } 297 298 kfree(kobjp); 299 return 0; 300 301 out_clean_nodes: 302 for (j = i - 1; j >= 0; j--) 303 cleanup_setup_data_node(*(kobjp + j)); 304 kfree(kobjp); 305 out_setup_data_kobj: 306 kobject_put(setup_data_kobj); 307 out: 308 return ret; 309 } 310 311 static int __init boot_params_ksysfs_init(void) 312 { 313 int ret; 314 struct kobject *boot_params_kobj; 315 316 boot_params_kobj = kobject_create_and_add("boot_params", 317 kernel_kobj); 318 if (!boot_params_kobj) { 319 ret = -ENOMEM; 320 goto out; 321 } 322 323 ret = sysfs_create_group(boot_params_kobj, &boot_params_attr_group); 324 if (ret) 325 goto out_boot_params_kobj; 326 327 ret = create_setup_data_nodes(boot_params_kobj); 328 if (ret) 329 goto out_create_group; 330 331 return 0; 332 out_create_group: 333 sysfs_remove_group(boot_params_kobj, &boot_params_attr_group); 334 out_boot_params_kobj: 335 kobject_put(boot_params_kobj); 336 out: 337 return ret; 338 } 339 340 arch_initcall(boot_params_ksysfs_init); 341