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