1 // SPDX-License-Identifier: GPL-2.0-only
3 * Architecture specific sysfs attributes in /sys/kernel
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>
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>
20 #include <asm/setup.h>
22 static ssize_t
version_show(struct kobject
*kobj
,
23 struct kobj_attribute
*attr
, char *buf
)
25 return sprintf(buf
, "0x%04x\n", boot_params
.hdr
.version
);
28 static struct kobj_attribute boot_params_version_attr
= __ATTR_RO(version
);
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
)
34 memcpy(buf
, (void *)&boot_params
+ off
, count
);
38 static struct bin_attribute boot_params_data_attr
= {
43 .read
= boot_params_data_read
,
44 .size
= sizeof(boot_params
),
47 static struct attribute
*boot_params_version_attrs
[] = {
48 &boot_params_version_attr
.attr
,
52 static struct bin_attribute
*boot_params_data_attrs
[] = {
53 &boot_params_data_attr
,
57 static const struct attribute_group boot_params_attr_group
= {
58 .attrs
= boot_params_version_attrs
,
59 .bin_attrs
= boot_params_data_attrs
,
62 static int kobj_to_setup_data_nr(struct kobject
*kobj
, int *nr
)
66 name
= kobject_name(kobj
);
67 return kstrtoint(name
, 10, nr
);
70 static int get_setup_data_paddr(int nr
, u64
*paddr
)
73 struct setup_data
*data
;
74 u64 pa_data
= boot_params
.hdr
.setup_data
;
81 data
= memremap(pa_data
, sizeof(*data
), MEMREMAP_WB
);
92 static int __init
get_setup_data_size(int nr
, size_t *size
)
94 u64 pa_data
= boot_params
.hdr
.setup_data
, pa_next
;
95 struct setup_indirect
*indirect
;
96 struct setup_data
*data
;
101 data
= memremap(pa_data
, sizeof(*data
), MEMREMAP_WB
);
104 pa_next
= data
->next
;
107 if (data
->type
== SETUP_INDIRECT
) {
108 len
= sizeof(*data
) + data
->len
;
110 data
= memremap(pa_data
, len
, MEMREMAP_WB
);
114 indirect
= (struct setup_indirect
*)data
->data
;
116 if (indirect
->type
!= SETUP_INDIRECT
)
117 *size
= indirect
->len
;
135 static ssize_t
type_show(struct kobject
*kobj
,
136 struct kobj_attribute
*attr
, char *buf
)
138 struct setup_indirect
*indirect
;
139 struct setup_data
*data
;
144 ret
= kobj_to_setup_data_nr(kobj
, &nr
);
148 ret
= get_setup_data_paddr(nr
, &paddr
);
151 data
= memremap(paddr
, sizeof(*data
), MEMREMAP_WB
);
155 if (data
->type
== SETUP_INDIRECT
) {
156 len
= sizeof(*data
) + data
->len
;
158 data
= memremap(paddr
, len
, MEMREMAP_WB
);
162 indirect
= (struct setup_indirect
*)data
->data
;
164 ret
= sprintf(buf
, "0x%x\n", indirect
->type
);
166 ret
= sprintf(buf
, "0x%x\n", data
->type
);
173 static ssize_t
setup_data_data_read(struct file
*fp
,
174 struct kobject
*kobj
,
175 struct bin_attribute
*bin_attr
,
177 loff_t off
, size_t count
)
179 struct setup_indirect
*indirect
;
180 struct setup_data
*data
;
185 ret
= kobj_to_setup_data_nr(kobj
, &nr
);
189 ret
= get_setup_data_paddr(nr
, &paddr
);
192 data
= memremap(paddr
, sizeof(*data
), MEMREMAP_WB
);
196 if (data
->type
== SETUP_INDIRECT
) {
197 len
= sizeof(*data
) + data
->len
;
199 data
= memremap(paddr
, len
, MEMREMAP_WB
);
203 indirect
= (struct setup_indirect
*)data
->data
;
205 if (indirect
->type
!= SETUP_INDIRECT
) {
206 paddr
= indirect
->addr
;
210 * Even though this is technically undefined, return
211 * the data as though it is a normal setup_data struct.
212 * This will at least allow it to be inspected.
214 paddr
+= sizeof(*data
);
218 paddr
+= sizeof(*data
);
227 if (count
> len
- off
)
234 p
= memremap(paddr
, len
, MEMREMAP_WB
);
239 memcpy(buf
, p
+ off
, count
);
246 static struct kobj_attribute type_attr
= __ATTR_RO(type
);
248 static struct bin_attribute data_attr __ro_after_init
= {
253 .read
= setup_data_data_read
,
256 static struct attribute
*setup_data_type_attrs
[] = {
261 static struct bin_attribute
*setup_data_data_attrs
[] = {
266 static const struct attribute_group setup_data_attr_group
= {
267 .attrs
= setup_data_type_attrs
,
268 .bin_attrs
= setup_data_data_attrs
,
271 static int __init
create_setup_data_node(struct kobject
*parent
,
272 struct kobject
**kobjp
, int nr
)
276 struct kobject
*kobj
;
277 char name
[16]; /* should be enough for setup_data nodes numbers */
278 snprintf(name
, 16, "%d", nr
);
280 kobj
= kobject_create_and_add(name
, parent
);
284 ret
= get_setup_data_size(nr
, &size
);
288 data_attr
.size
= size
;
289 ret
= sysfs_create_group(kobj
, &setup_data_attr_group
);
300 static void __init
cleanup_setup_data_node(struct kobject
*kobj
)
302 sysfs_remove_group(kobj
, &setup_data_attr_group
);
306 static int __init
get_setup_data_total_num(u64 pa_data
, int *nr
)
309 struct setup_data
*data
;
314 data
= memremap(pa_data
, sizeof(*data
), MEMREMAP_WB
);
319 pa_data
= data
->next
;
327 static int __init
create_setup_data_nodes(struct kobject
*parent
)
329 struct kobject
*setup_data_kobj
, **kobjp
;
331 int i
, j
, nr
, ret
= 0;
333 pa_data
= boot_params
.hdr
.setup_data
;
337 setup_data_kobj
= kobject_create_and_add("setup_data", parent
);
338 if (!setup_data_kobj
) {
343 ret
= get_setup_data_total_num(pa_data
, &nr
);
345 goto out_setup_data_kobj
;
347 kobjp
= kmalloc_array(nr
, sizeof(*kobjp
), GFP_KERNEL
);
350 goto out_setup_data_kobj
;
353 for (i
= 0; i
< nr
; i
++) {
354 ret
= create_setup_data_node(setup_data_kobj
, kobjp
+ i
, i
);
356 goto out_clean_nodes
;
363 for (j
= i
- 1; j
>= 0; j
--)
364 cleanup_setup_data_node(*(kobjp
+ j
));
367 kobject_put(setup_data_kobj
);
372 static int __init
boot_params_ksysfs_init(void)
375 struct kobject
*boot_params_kobj
;
377 boot_params_kobj
= kobject_create_and_add("boot_params",
379 if (!boot_params_kobj
) {
384 ret
= sysfs_create_group(boot_params_kobj
, &boot_params_attr_group
);
386 goto out_boot_params_kobj
;
388 ret
= create_setup_data_nodes(boot_params_kobj
);
390 goto out_create_group
;
394 sysfs_remove_group(boot_params_kobj
, &boot_params_attr_group
);
395 out_boot_params_kobj
:
396 kobject_put(boot_params_kobj
);
401 arch_initcall(boot_params_ksysfs_init
);