LCOV - code coverage report
Current view: top level - arch/x86/kernel - ksysfs.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 15 175 8.6 %
Date: 2021-04-22 12:43:58 Functions: 2 11 18.2 %

          Line data    Source code
       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           0 : static ssize_t version_show(struct kobject *kobj,
      23             :                             struct kobj_attribute *attr, char *buf)
      24             : {
      25           0 :         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           0 : 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           0 :         memcpy(buf, (void *)&boot_params + off, count);
      35           0 :         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           0 : static int kobj_to_setup_data_nr(struct kobject *kobj, int *nr)
      63             : {
      64           0 :         const char *name;
      65             : 
      66           0 :         name = kobject_name(kobj);
      67           0 :         return kstrtoint(name, 10, nr);
      68             : }
      69             : 
      70           0 : static int get_setup_data_paddr(int nr, u64 *paddr)
      71             : {
      72           0 :         int i = 0;
      73           0 :         struct setup_data *data;
      74           0 :         u64 pa_data = boot_params.hdr.setup_data;
      75             : 
      76           0 :         while (pa_data) {
      77           0 :                 if (nr == i) {
      78           0 :                         *paddr = pa_data;
      79           0 :                         return 0;
      80             :                 }
      81           0 :                 data = memremap(pa_data, sizeof(*data), MEMREMAP_WB);
      82           0 :                 if (!data)
      83             :                         return -ENOMEM;
      84             : 
      85           0 :                 pa_data = data->next;
      86           0 :                 memunmap(data);
      87           0 :                 i++;
      88             :         }
      89             :         return -EINVAL;
      90             : }
      91             : 
      92           0 : static int __init get_setup_data_size(int nr, size_t *size)
      93             : {
      94           0 :         int i = 0;
      95           0 :         struct setup_data *data;
      96           0 :         u64 pa_data = boot_params.hdr.setup_data;
      97             : 
      98           0 :         while (pa_data) {
      99           0 :                 data = memremap(pa_data, sizeof(*data), MEMREMAP_WB);
     100           0 :                 if (!data)
     101             :                         return -ENOMEM;
     102           0 :                 if (nr == i) {
     103           0 :                         if (data->type == SETUP_INDIRECT &&
     104           0 :                             ((struct setup_indirect *)data->data)->type != SETUP_INDIRECT)
     105           0 :                                 *size = ((struct setup_indirect *)data->data)->len;
     106             :                         else
     107           0 :                                 *size = data->len;
     108             : 
     109           0 :                         memunmap(data);
     110           0 :                         return 0;
     111             :                 }
     112             : 
     113           0 :                 pa_data = data->next;
     114           0 :                 memunmap(data);
     115           0 :                 i++;
     116             :         }
     117             :         return -EINVAL;
     118             : }
     119             : 
     120           0 : static ssize_t type_show(struct kobject *kobj,
     121             :                          struct kobj_attribute *attr, char *buf)
     122             : {
     123           0 :         int nr, ret;
     124           0 :         u64 paddr;
     125           0 :         struct setup_data *data;
     126             : 
     127           0 :         ret = kobj_to_setup_data_nr(kobj, &nr);
     128           0 :         if (ret)
     129           0 :                 return ret;
     130             : 
     131           0 :         ret = get_setup_data_paddr(nr, &paddr);
     132           0 :         if (ret)
     133           0 :                 return ret;
     134           0 :         data = memremap(paddr, sizeof(*data), MEMREMAP_WB);
     135           0 :         if (!data)
     136             :                 return -ENOMEM;
     137             : 
     138           0 :         if (data->type == SETUP_INDIRECT)
     139           0 :                 ret = sprintf(buf, "0x%x\n", ((struct setup_indirect *)data->data)->type);
     140             :         else
     141           0 :                 ret = sprintf(buf, "0x%x\n", data->type);
     142           0 :         memunmap(data);
     143           0 :         return ret;
     144             : }
     145             : 
     146           0 : 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           0 :         int nr, ret = 0;
     153           0 :         u64 paddr, len;
     154           0 :         struct setup_data *data;
     155           0 :         void *p;
     156             : 
     157           0 :         ret = kobj_to_setup_data_nr(kobj, &nr);
     158           0 :         if (ret)
     159           0 :                 return ret;
     160             : 
     161           0 :         ret = get_setup_data_paddr(nr, &paddr);
     162           0 :         if (ret)
     163           0 :                 return ret;
     164           0 :         data = memremap(paddr, sizeof(*data), MEMREMAP_WB);
     165           0 :         if (!data)
     166             :                 return -ENOMEM;
     167             : 
     168           0 :         if (data->type == SETUP_INDIRECT &&
     169           0 :             ((struct setup_indirect *)data->data)->type != SETUP_INDIRECT) {
     170           0 :                 paddr = ((struct setup_indirect *)data->data)->addr;
     171           0 :                 len = ((struct setup_indirect *)data->data)->len;
     172             :         } else {
     173           0 :                 paddr += sizeof(*data);
     174           0 :                 len = data->len;
     175             :         }
     176             : 
     177           0 :         if (off > len) {
     178           0 :                 ret = -EINVAL;
     179           0 :                 goto out;
     180             :         }
     181             : 
     182           0 :         if (count > len - off)
     183             :                 count = len - off;
     184             : 
     185           0 :         if (!count)
     186           0 :                 goto out;
     187             : 
     188           0 :         ret = count;
     189           0 :         p = memremap(paddr, len, MEMREMAP_WB);
     190           0 :         if (!p) {
     191           0 :                 ret = -ENOMEM;
     192           0 :                 goto out;
     193             :         }
     194           0 :         memcpy(buf, p + off, count);
     195           0 :         memunmap(p);
     196           0 : out:
     197           0 :         memunmap(data);
     198           0 :         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           0 : static int __init create_setup_data_node(struct kobject *parent,
     227             :                                          struct kobject **kobjp, int nr)
     228             : {
     229           0 :         int ret = 0;
     230           0 :         size_t size;
     231           0 :         struct kobject *kobj;
     232           0 :         char name[16]; /* should be enough for setup_data nodes numbers */
     233           0 :         snprintf(name, 16, "%d", nr);
     234             : 
     235           0 :         kobj = kobject_create_and_add(name, parent);
     236           0 :         if (!kobj)
     237             :                 return -ENOMEM;
     238             : 
     239           0 :         ret = get_setup_data_size(nr, &size);
     240           0 :         if (ret)
     241           0 :                 goto out_kobj;
     242             : 
     243           0 :         data_attr.size = size;
     244           0 :         ret = sysfs_create_group(kobj, &setup_data_attr_group);
     245           0 :         if (ret)
     246           0 :                 goto out_kobj;
     247           0 :         *kobjp = kobj;
     248             : 
     249           0 :         return 0;
     250           0 : out_kobj:
     251           0 :         kobject_put(kobj);
     252           0 :         return ret;
     253             : }
     254             : 
     255           0 : static void __init cleanup_setup_data_node(struct kobject *kobj)
     256             : {
     257           0 :         sysfs_remove_group(kobj, &setup_data_attr_group);
     258           0 :         kobject_put(kobj);
     259           0 : }
     260             : 
     261           0 : static int __init get_setup_data_total_num(u64 pa_data, int *nr)
     262             : {
     263           0 :         int ret = 0;
     264           0 :         struct setup_data *data;
     265             : 
     266           0 :         *nr = 0;
     267           0 :         while (pa_data) {
     268           0 :                 *nr += 1;
     269           0 :                 data = memremap(pa_data, sizeof(*data), MEMREMAP_WB);
     270           0 :                 if (!data) {
     271           0 :                         ret = -ENOMEM;
     272           0 :                         goto out;
     273             :                 }
     274           0 :                 pa_data = data->next;
     275           0 :                 memunmap(data);
     276             :         }
     277             : 
     278           0 : out:
     279           0 :         return ret;
     280             : }
     281             : 
     282           1 : static int __init create_setup_data_nodes(struct kobject *parent)
     283             : {
     284           1 :         struct kobject *setup_data_kobj, **kobjp;
     285           1 :         u64 pa_data;
     286           1 :         int i, j, nr, ret = 0;
     287             : 
     288           1 :         pa_data = boot_params.hdr.setup_data;
     289           1 :         if (!pa_data)
     290             :                 return 0;
     291             : 
     292           0 :         setup_data_kobj = kobject_create_and_add("setup_data", parent);
     293           0 :         if (!setup_data_kobj) {
     294           0 :                 ret = -ENOMEM;
     295           0 :                 goto out;
     296             :         }
     297             : 
     298           0 :         ret = get_setup_data_total_num(pa_data, &nr);
     299           0 :         if (ret)
     300           0 :                 goto out_setup_data_kobj;
     301             : 
     302           0 :         kobjp = kmalloc_array(nr, sizeof(*kobjp), GFP_KERNEL);
     303           0 :         if (!kobjp) {
     304           0 :                 ret = -ENOMEM;
     305           0 :                 goto out_setup_data_kobj;
     306             :         }
     307             : 
     308           0 :         for (i = 0; i < nr; i++) {
     309           0 :                 ret = create_setup_data_node(setup_data_kobj, kobjp + i, i);
     310           0 :                 if (ret)
     311           0 :                         goto out_clean_nodes;
     312             :         }
     313             : 
     314           0 :         kfree(kobjp);
     315           0 :         return 0;
     316             : 
     317           0 : out_clean_nodes:
     318           0 :         for (j = i - 1; j >= 0; j--)
     319           0 :                 cleanup_setup_data_node(*(kobjp + j));
     320           0 :         kfree(kobjp);
     321           0 : out_setup_data_kobj:
     322           0 :         kobject_put(setup_data_kobj);
     323             : out:
     324             :         return ret;
     325             : }
     326             : 
     327           1 : static int __init boot_params_ksysfs_init(void)
     328             : {
     329           1 :         int ret;
     330           1 :         struct kobject *boot_params_kobj;
     331             : 
     332           1 :         boot_params_kobj = kobject_create_and_add("boot_params",
     333             :                                                   kernel_kobj);
     334           1 :         if (!boot_params_kobj) {
     335           0 :                 ret = -ENOMEM;
     336           0 :                 goto out;
     337             :         }
     338             : 
     339           1 :         ret = sysfs_create_group(boot_params_kobj, &boot_params_attr_group);
     340           1 :         if (ret)
     341           0 :                 goto out_boot_params_kobj;
     342             : 
     343           1 :         ret = create_setup_data_nodes(boot_params_kobj);
     344           1 :         if (ret)
     345           0 :                 goto out_create_group;
     346             : 
     347             :         return 0;
     348           0 : out_create_group:
     349           0 :         sysfs_remove_group(boot_params_kobj, &boot_params_attr_group);
     350           0 : out_boot_params_kobj:
     351           0 :         kobject_put(boot_params_kobj);
     352             : out:
     353             :         return ret;
     354             : }
     355             : 
     356             : arch_initcall(boot_params_ksysfs_init);

Generated by: LCOV version 1.14