linux/arch/x86/kernel/ksysfs.c
<<
>>
Prefs
   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
  20#include <asm/io.h>
  21#include <asm/setup.h>
  22
  23static 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
  29static struct kobj_attribute boot_params_version_attr = __ATTR_RO(version);
  30
  31static 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
  39static 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
  48static struct attribute *boot_params_version_attrs[] = {
  49        &boot_params_version_attr.attr,
  50        NULL,
  51};
  52
  53static struct bin_attribute *boot_params_data_attrs[] = {
  54        &boot_params_data_attr,
  55        NULL,
  56};
  57
  58static struct attribute_group boot_params_attr_group = {
  59        .attrs = boot_params_version_attrs,
  60        .bin_attrs = boot_params_data_attrs,
  61};
  62
  63static 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
  71static 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 = ioremap_cache(pa_data, sizeof(*data));
  83                if (!data)
  84                        return -ENOMEM;
  85
  86                pa_data = data->next;
  87                iounmap(data);
  88                i++;
  89        }
  90        return -EINVAL;
  91}
  92
  93static 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 = ioremap_cache(pa_data, sizeof(*data));
 101                if (!data)
 102                        return -ENOMEM;
 103                if (nr == i) {
 104                        *size = data->len;
 105                        iounmap(data);
 106                        return 0;
 107                }
 108
 109                pa_data = data->next;
 110                iounmap(data);
 111                i++;
 112        }
 113        return -EINVAL;
 114}
 115
 116static 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 = ioremap_cache(paddr, sizeof(*data));
 131        if (!data)
 132                return -ENOMEM;
 133
 134        ret = sprintf(buf, "0x%x\n", data->type);
 135        iounmap(data);
 136        return ret;
 137}
 138
 139static 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 = ioremap_cache(paddr, sizeof(*data));
 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 = ioremap_cache(paddr + sizeof(*data), data->len);
 174        if (!p) {
 175                ret = -ENOMEM;
 176                goto out;
 177        }
 178        memcpy(buf, p + off, count);
 179        iounmap(p);
 180out:
 181        iounmap(data);
 182        return ret;
 183}
 184
 185static struct kobj_attribute type_attr = __ATTR_RO(type);
 186
 187static struct bin_attribute data_attr = {
 188        .attr = {
 189                .name = "data",
 190                .mode = S_IRUGO,
 191        },
 192        .read = setup_data_data_read,
 193};
 194
 195static struct attribute *setup_data_type_attrs[] = {
 196        &type_attr.attr,
 197        NULL,
 198};
 199
 200static struct bin_attribute *setup_data_data_attrs[] = {
 201        &data_attr,
 202        NULL,
 203};
 204
 205static struct attribute_group setup_data_attr_group = {
 206        .attrs = setup_data_type_attrs,
 207        .bin_attrs = setup_data_data_attrs,
 208};
 209
 210static 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;
 234out_kobj:
 235        kobject_put(kobj);
 236        return ret;
 237}
 238
 239static 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
 245static 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 = ioremap_cache(pa_data, sizeof(*data));
 254                if (!data) {
 255                        ret = -ENOMEM;
 256                        goto out;
 257                }
 258                pa_data = data->next;
 259                iounmap(data);
 260        }
 261
 262out:
 263        return ret;
 264}
 265
 266static 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
 301out_clean_nodes:
 302        for (j = i - 1; j > 0; j--)
 303                cleanup_setup_data_node(*(kobjp + j));
 304        kfree(kobjp);
 305out_setup_data_kobj:
 306        kobject_put(setup_data_kobj);
 307out:
 308        return ret;
 309}
 310
 311static 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;
 332out_create_group:
 333        sysfs_remove_group(boot_params_kobj, &boot_params_attr_group);
 334out_boot_params_kobj:
 335        kobject_put(boot_params_kobj);
 336out:
 337        return ret;
 338}
 339
 340arch_initcall(boot_params_ksysfs_init);
 341