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
)
95 struct setup_data
*data
;
96 u64 pa_data
= boot_params
.hdr
.setup_data
;
99 data
= memremap(pa_data
, sizeof(*data
), MEMREMAP_WB
);
103 if (data
->type
== SETUP_INDIRECT
&&
104 ((struct setup_indirect
*)data
->data
)->type
!= SETUP_INDIRECT
)
105 *size
= ((struct setup_indirect
*)data
->data
)->len
;
113 pa_data
= data
->next
;
120 static ssize_t
type_show(struct kobject
*kobj
,
121 struct kobj_attribute
*attr
, char *buf
)
125 struct setup_data
*data
;
127 ret
= kobj_to_setup_data_nr(kobj
, &nr
);
131 ret
= get_setup_data_paddr(nr
, &paddr
);
134 data
= memremap(paddr
, sizeof(*data
), MEMREMAP_WB
);
138 if (data
->type
== SETUP_INDIRECT
)
139 ret
= sprintf(buf
, "0x%x\n", ((struct setup_indirect
*)data
->data
)->type
);
141 ret
= sprintf(buf
, "0x%x\n", data
->type
);
146 static ssize_t
setup_data_data_read(struct file
*fp
,
147 struct kobject
*kobj
,
148 struct bin_attribute
*bin_attr
,
150 loff_t off
, size_t count
)
154 struct setup_data
*data
;
157 ret
= kobj_to_setup_data_nr(kobj
, &nr
);
161 ret
= get_setup_data_paddr(nr
, &paddr
);
164 data
= memremap(paddr
, sizeof(*data
), MEMREMAP_WB
);
168 if (data
->type
== SETUP_INDIRECT
&&
169 ((struct setup_indirect
*)data
->data
)->type
!= SETUP_INDIRECT
) {
170 paddr
= ((struct setup_indirect
*)data
->data
)->addr
;
171 len
= ((struct setup_indirect
*)data
->data
)->len
;
173 paddr
+= sizeof(*data
);
182 if (count
> len
- off
)
189 p
= memremap(paddr
, len
, MEMREMAP_WB
);
194 memcpy(buf
, p
+ off
, count
);
201 static struct kobj_attribute type_attr
= __ATTR_RO(type
);
203 static struct bin_attribute data_attr __ro_after_init
= {
208 .read
= setup_data_data_read
,
211 static struct attribute
*setup_data_type_attrs
[] = {
216 static struct bin_attribute
*setup_data_data_attrs
[] = {
221 static const struct attribute_group setup_data_attr_group
= {
222 .attrs
= setup_data_type_attrs
,
223 .bin_attrs
= setup_data_data_attrs
,
226 static int __init
create_setup_data_node(struct kobject
*parent
,
227 struct kobject
**kobjp
, int nr
)
231 struct kobject
*kobj
;
232 char name
[16]; /* should be enough for setup_data nodes numbers */
233 snprintf(name
, 16, "%d", nr
);
235 kobj
= kobject_create_and_add(name
, parent
);
239 ret
= get_setup_data_size(nr
, &size
);
243 data_attr
.size
= size
;
244 ret
= sysfs_create_group(kobj
, &setup_data_attr_group
);
255 static void __init
cleanup_setup_data_node(struct kobject
*kobj
)
257 sysfs_remove_group(kobj
, &setup_data_attr_group
);
261 static int __init
get_setup_data_total_num(u64 pa_data
, int *nr
)
264 struct setup_data
*data
;
269 data
= memremap(pa_data
, sizeof(*data
), MEMREMAP_WB
);
274 pa_data
= data
->next
;
282 static int __init
create_setup_data_nodes(struct kobject
*parent
)
284 struct kobject
*setup_data_kobj
, **kobjp
;
286 int i
, j
, nr
, ret
= 0;
288 pa_data
= boot_params
.hdr
.setup_data
;
292 setup_data_kobj
= kobject_create_and_add("setup_data", parent
);
293 if (!setup_data_kobj
) {
298 ret
= get_setup_data_total_num(pa_data
, &nr
);
300 goto out_setup_data_kobj
;
302 kobjp
= kmalloc_array(nr
, sizeof(*kobjp
), GFP_KERNEL
);
305 goto out_setup_data_kobj
;
308 for (i
= 0; i
< nr
; i
++) {
309 ret
= create_setup_data_node(setup_data_kobj
, kobjp
+ i
, i
);
311 goto out_clean_nodes
;
318 for (j
= i
- 1; j
>= 0; j
--)
319 cleanup_setup_data_node(*(kobjp
+ j
));
322 kobject_put(setup_data_kobj
);
327 static int __init
boot_params_ksysfs_init(void)
330 struct kobject
*boot_params_kobj
;
332 boot_params_kobj
= kobject_create_and_add("boot_params",
334 if (!boot_params_kobj
) {
339 ret
= sysfs_create_group(boot_params_kobj
, &boot_params_attr_group
);
341 goto out_boot_params_kobj
;
343 ret
= create_setup_data_nodes(boot_params_kobj
);
345 goto out_create_group
;
349 sysfs_remove_group(boot_params_kobj
, &boot_params_attr_group
);
350 out_boot_params_kobj
:
351 kobject_put(boot_params_kobj
);
356 arch_initcall(boot_params_ksysfs_init
);