ksysfs.c 7.9 KB

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