0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/kobject.h>
0012 #include <linux/string.h>
0013 #include <linux/sysfs.h>
0014 #include <linux/init.h>
0015 #include <linux/stat.h>
0016 #include <linux/slab.h>
0017 #include <linux/mm.h>
0018 #include <linux/io.h>
0019
0020 #include <asm/setup.h>
0021
0022 static ssize_t version_show(struct kobject *kobj,
0023 struct kobj_attribute *attr, char *buf)
0024 {
0025 return sprintf(buf, "0x%04x\n", boot_params.hdr.version);
0026 }
0027
0028 static struct kobj_attribute boot_params_version_attr = __ATTR_RO(version);
0029
0030 static ssize_t boot_params_data_read(struct file *fp, struct kobject *kobj,
0031 struct bin_attribute *bin_attr,
0032 char *buf, loff_t off, size_t count)
0033 {
0034 memcpy(buf, (void *)&boot_params + off, count);
0035 return count;
0036 }
0037
0038 static struct bin_attribute boot_params_data_attr = {
0039 .attr = {
0040 .name = "data",
0041 .mode = S_IRUGO,
0042 },
0043 .read = boot_params_data_read,
0044 .size = sizeof(boot_params),
0045 };
0046
0047 static struct attribute *boot_params_version_attrs[] = {
0048 &boot_params_version_attr.attr,
0049 NULL,
0050 };
0051
0052 static struct bin_attribute *boot_params_data_attrs[] = {
0053 &boot_params_data_attr,
0054 NULL,
0055 };
0056
0057 static const struct attribute_group boot_params_attr_group = {
0058 .attrs = boot_params_version_attrs,
0059 .bin_attrs = boot_params_data_attrs,
0060 };
0061
0062 static int kobj_to_setup_data_nr(struct kobject *kobj, int *nr)
0063 {
0064 const char *name;
0065
0066 name = kobject_name(kobj);
0067 return kstrtoint(name, 10, nr);
0068 }
0069
0070 static int get_setup_data_paddr(int nr, u64 *paddr)
0071 {
0072 int i = 0;
0073 struct setup_data *data;
0074 u64 pa_data = boot_params.hdr.setup_data;
0075
0076 while (pa_data) {
0077 if (nr == i) {
0078 *paddr = pa_data;
0079 return 0;
0080 }
0081 data = memremap(pa_data, sizeof(*data), MEMREMAP_WB);
0082 if (!data)
0083 return -ENOMEM;
0084
0085 pa_data = data->next;
0086 memunmap(data);
0087 i++;
0088 }
0089 return -EINVAL;
0090 }
0091
0092 static int __init get_setup_data_size(int nr, size_t *size)
0093 {
0094 u64 pa_data = boot_params.hdr.setup_data, pa_next;
0095 struct setup_indirect *indirect;
0096 struct setup_data *data;
0097 int i = 0;
0098 u32 len;
0099
0100 while (pa_data) {
0101 data = memremap(pa_data, sizeof(*data), MEMREMAP_WB);
0102 if (!data)
0103 return -ENOMEM;
0104 pa_next = data->next;
0105
0106 if (nr == i) {
0107 if (data->type == SETUP_INDIRECT) {
0108 len = sizeof(*data) + data->len;
0109 memunmap(data);
0110 data = memremap(pa_data, len, MEMREMAP_WB);
0111 if (!data)
0112 return -ENOMEM;
0113
0114 indirect = (struct setup_indirect *)data->data;
0115
0116 if (indirect->type != SETUP_INDIRECT)
0117 *size = indirect->len;
0118 else
0119 *size = data->len;
0120 } else {
0121 *size = data->len;
0122 }
0123
0124 memunmap(data);
0125 return 0;
0126 }
0127
0128 pa_data = pa_next;
0129 memunmap(data);
0130 i++;
0131 }
0132 return -EINVAL;
0133 }
0134
0135 static ssize_t type_show(struct kobject *kobj,
0136 struct kobj_attribute *attr, char *buf)
0137 {
0138 struct setup_indirect *indirect;
0139 struct setup_data *data;
0140 int nr, ret;
0141 u64 paddr;
0142 u32 len;
0143
0144 ret = kobj_to_setup_data_nr(kobj, &nr);
0145 if (ret)
0146 return ret;
0147
0148 ret = get_setup_data_paddr(nr, &paddr);
0149 if (ret)
0150 return ret;
0151 data = memremap(paddr, sizeof(*data), MEMREMAP_WB);
0152 if (!data)
0153 return -ENOMEM;
0154
0155 if (data->type == SETUP_INDIRECT) {
0156 len = sizeof(*data) + data->len;
0157 memunmap(data);
0158 data = memremap(paddr, len, MEMREMAP_WB);
0159 if (!data)
0160 return -ENOMEM;
0161
0162 indirect = (struct setup_indirect *)data->data;
0163
0164 ret = sprintf(buf, "0x%x\n", indirect->type);
0165 } else {
0166 ret = sprintf(buf, "0x%x\n", data->type);
0167 }
0168
0169 memunmap(data);
0170 return ret;
0171 }
0172
0173 static ssize_t setup_data_data_read(struct file *fp,
0174 struct kobject *kobj,
0175 struct bin_attribute *bin_attr,
0176 char *buf,
0177 loff_t off, size_t count)
0178 {
0179 struct setup_indirect *indirect;
0180 struct setup_data *data;
0181 int nr, ret = 0;
0182 u64 paddr, len;
0183 void *p;
0184
0185 ret = kobj_to_setup_data_nr(kobj, &nr);
0186 if (ret)
0187 return ret;
0188
0189 ret = get_setup_data_paddr(nr, &paddr);
0190 if (ret)
0191 return ret;
0192 data = memremap(paddr, sizeof(*data), MEMREMAP_WB);
0193 if (!data)
0194 return -ENOMEM;
0195
0196 if (data->type == SETUP_INDIRECT) {
0197 len = sizeof(*data) + data->len;
0198 memunmap(data);
0199 data = memremap(paddr, len, MEMREMAP_WB);
0200 if (!data)
0201 return -ENOMEM;
0202
0203 indirect = (struct setup_indirect *)data->data;
0204
0205 if (indirect->type != SETUP_INDIRECT) {
0206 paddr = indirect->addr;
0207 len = indirect->len;
0208 } else {
0209
0210
0211
0212
0213
0214 paddr += sizeof(*data);
0215 len = data->len;
0216 }
0217 } else {
0218 paddr += sizeof(*data);
0219 len = data->len;
0220 }
0221
0222 if (off > len) {
0223 ret = -EINVAL;
0224 goto out;
0225 }
0226
0227 if (count > len - off)
0228 count = len - off;
0229
0230 if (!count)
0231 goto out;
0232
0233 ret = count;
0234 p = memremap(paddr, len, MEMREMAP_WB);
0235 if (!p) {
0236 ret = -ENOMEM;
0237 goto out;
0238 }
0239 memcpy(buf, p + off, count);
0240 memunmap(p);
0241 out:
0242 memunmap(data);
0243 return ret;
0244 }
0245
0246 static struct kobj_attribute type_attr = __ATTR_RO(type);
0247
0248 static struct bin_attribute data_attr __ro_after_init = {
0249 .attr = {
0250 .name = "data",
0251 .mode = S_IRUGO,
0252 },
0253 .read = setup_data_data_read,
0254 };
0255
0256 static struct attribute *setup_data_type_attrs[] = {
0257 &type_attr.attr,
0258 NULL,
0259 };
0260
0261 static struct bin_attribute *setup_data_data_attrs[] = {
0262 &data_attr,
0263 NULL,
0264 };
0265
0266 static const struct attribute_group setup_data_attr_group = {
0267 .attrs = setup_data_type_attrs,
0268 .bin_attrs = setup_data_data_attrs,
0269 };
0270
0271 static int __init create_setup_data_node(struct kobject *parent,
0272 struct kobject **kobjp, int nr)
0273 {
0274 int ret = 0;
0275 size_t size;
0276 struct kobject *kobj;
0277 char name[16];
0278 snprintf(name, 16, "%d", nr);
0279
0280 kobj = kobject_create_and_add(name, parent);
0281 if (!kobj)
0282 return -ENOMEM;
0283
0284 ret = get_setup_data_size(nr, &size);
0285 if (ret)
0286 goto out_kobj;
0287
0288 data_attr.size = size;
0289 ret = sysfs_create_group(kobj, &setup_data_attr_group);
0290 if (ret)
0291 goto out_kobj;
0292 *kobjp = kobj;
0293
0294 return 0;
0295 out_kobj:
0296 kobject_put(kobj);
0297 return ret;
0298 }
0299
0300 static void __init cleanup_setup_data_node(struct kobject *kobj)
0301 {
0302 sysfs_remove_group(kobj, &setup_data_attr_group);
0303 kobject_put(kobj);
0304 }
0305
0306 static int __init get_setup_data_total_num(u64 pa_data, int *nr)
0307 {
0308 int ret = 0;
0309 struct setup_data *data;
0310
0311 *nr = 0;
0312 while (pa_data) {
0313 *nr += 1;
0314 data = memremap(pa_data, sizeof(*data), MEMREMAP_WB);
0315 if (!data) {
0316 ret = -ENOMEM;
0317 goto out;
0318 }
0319 pa_data = data->next;
0320 memunmap(data);
0321 }
0322
0323 out:
0324 return ret;
0325 }
0326
0327 static int __init create_setup_data_nodes(struct kobject *parent)
0328 {
0329 struct kobject *setup_data_kobj, **kobjp;
0330 u64 pa_data;
0331 int i, j, nr, ret = 0;
0332
0333 pa_data = boot_params.hdr.setup_data;
0334 if (!pa_data)
0335 return 0;
0336
0337 setup_data_kobj = kobject_create_and_add("setup_data", parent);
0338 if (!setup_data_kobj) {
0339 ret = -ENOMEM;
0340 goto out;
0341 }
0342
0343 ret = get_setup_data_total_num(pa_data, &nr);
0344 if (ret)
0345 goto out_setup_data_kobj;
0346
0347 kobjp = kmalloc_array(nr, sizeof(*kobjp), GFP_KERNEL);
0348 if (!kobjp) {
0349 ret = -ENOMEM;
0350 goto out_setup_data_kobj;
0351 }
0352
0353 for (i = 0; i < nr; i++) {
0354 ret = create_setup_data_node(setup_data_kobj, kobjp + i, i);
0355 if (ret)
0356 goto out_clean_nodes;
0357 }
0358
0359 kfree(kobjp);
0360 return 0;
0361
0362 out_clean_nodes:
0363 for (j = i - 1; j >= 0; j--)
0364 cleanup_setup_data_node(*(kobjp + j));
0365 kfree(kobjp);
0366 out_setup_data_kobj:
0367 kobject_put(setup_data_kobj);
0368 out:
0369 return ret;
0370 }
0371
0372 static int __init boot_params_ksysfs_init(void)
0373 {
0374 int ret;
0375 struct kobject *boot_params_kobj;
0376
0377 boot_params_kobj = kobject_create_and_add("boot_params",
0378 kernel_kobj);
0379 if (!boot_params_kobj) {
0380 ret = -ENOMEM;
0381 goto out;
0382 }
0383
0384 ret = sysfs_create_group(boot_params_kobj, &boot_params_attr_group);
0385 if (ret)
0386 goto out_boot_params_kobj;
0387
0388 ret = create_setup_data_nodes(boot_params_kobj);
0389 if (ret)
0390 goto out_create_group;
0391
0392 return 0;
0393 out_create_group:
0394 sysfs_remove_group(boot_params_kobj, &boot_params_attr_group);
0395 out_boot_params_kobj:
0396 kobject_put(boot_params_kobj);
0397 out:
0398 return ret;
0399 }
0400
0401 arch_initcall(boot_params_ksysfs_init);