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
);
108 pa_data
= data
->next
;
115 static ssize_t
type_show(struct kobject
*kobj
,
116 struct kobj_attribute
*attr
, char *buf
)
120 struct setup_data
*data
;
122 ret
= kobj_to_setup_data_nr(kobj
, &nr
);
126 ret
= get_setup_data_paddr(nr
, &paddr
);
129 data
= memremap(paddr
, sizeof(*data
), MEMREMAP_WB
);
133 ret
= sprintf(buf
, "0x%x\n", data
->type
);
138 static ssize_t
setup_data_data_read(struct file
*fp
,
139 struct kobject
*kobj
,
140 struct bin_attribute
*bin_attr
,
142 loff_t off
, size_t count
)
146 struct setup_data
*data
;
149 ret
= kobj_to_setup_data_nr(kobj
, &nr
);
153 ret
= get_setup_data_paddr(nr
, &paddr
);
156 data
= memremap(paddr
, sizeof(*data
), MEMREMAP_WB
);
160 if (off
> data
->len
) {
165 if (count
> data
->len
- off
)
166 count
= data
->len
- off
;
172 p
= memremap(paddr
+ sizeof(*data
), data
->len
, MEMREMAP_WB
);
177 memcpy(buf
, p
+ off
, count
);
184 static struct kobj_attribute type_attr
= __ATTR_RO(type
);
186 static struct bin_attribute data_attr __ro_after_init
= {
191 .read
= setup_data_data_read
,
194 static struct attribute
*setup_data_type_attrs
[] = {
199 static struct bin_attribute
*setup_data_data_attrs
[] = {
204 static const struct attribute_group setup_data_attr_group
= {
205 .attrs
= setup_data_type_attrs
,
206 .bin_attrs
= setup_data_data_attrs
,
209 static int __init
create_setup_data_node(struct kobject
*parent
,
210 struct kobject
**kobjp
, int nr
)
214 struct kobject
*kobj
;
215 char name
[16]; /* should be enough for setup_data nodes numbers */
216 snprintf(name
, 16, "%d", nr
);
218 kobj
= kobject_create_and_add(name
, parent
);
222 ret
= get_setup_data_size(nr
, &size
);
226 data_attr
.size
= size
;
227 ret
= sysfs_create_group(kobj
, &setup_data_attr_group
);
238 static void __init
cleanup_setup_data_node(struct kobject
*kobj
)
240 sysfs_remove_group(kobj
, &setup_data_attr_group
);
244 static int __init
get_setup_data_total_num(u64 pa_data
, int *nr
)
247 struct setup_data
*data
;
252 data
= memremap(pa_data
, sizeof(*data
), MEMREMAP_WB
);
257 pa_data
= data
->next
;
265 static int __init
create_setup_data_nodes(struct kobject
*parent
)
267 struct kobject
*setup_data_kobj
, **kobjp
;
269 int i
, j
, nr
, ret
= 0;
271 pa_data
= boot_params
.hdr
.setup_data
;
275 setup_data_kobj
= kobject_create_and_add("setup_data", parent
);
276 if (!setup_data_kobj
) {
281 ret
= get_setup_data_total_num(pa_data
, &nr
);
283 goto out_setup_data_kobj
;
285 kobjp
= kmalloc_array(nr
, sizeof(*kobjp
), GFP_KERNEL
);
288 goto out_setup_data_kobj
;
291 for (i
= 0; i
< nr
; i
++) {
292 ret
= create_setup_data_node(setup_data_kobj
, kobjp
+ i
, i
);
294 goto out_clean_nodes
;
301 for (j
= i
- 1; j
>= 0; j
--)
302 cleanup_setup_data_node(*(kobjp
+ j
));
305 kobject_put(setup_data_kobj
);
310 static int __init
boot_params_ksysfs_init(void)
313 struct kobject
*boot_params_kobj
;
315 boot_params_kobj
= kobject_create_and_add("boot_params",
317 if (!boot_params_kobj
) {
322 ret
= sysfs_create_group(boot_params_kobj
, &boot_params_attr_group
);
324 goto out_boot_params_kobj
;
326 ret
= create_setup_data_nodes(boot_params_kobj
);
328 goto out_create_group
;
332 sysfs_remove_group(boot_params_kobj
, &boot_params_attr_group
);
333 out_boot_params_kobj
:
334 kobject_put(boot_params_kobj
);
339 arch_initcall(boot_params_ksysfs_init
);