xref: /openbmc/linux/kernel/ksysfs.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1468e15fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * kernel/ksysfs.c - sysfs attributes in /sys/kernel, which
41da177e4SLinus Torvalds  * 		     are not related to any other subsystem
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
9d3d76fbdSThomas Weißschuh #include <asm/byteorder.h>
101da177e4SLinus Torvalds #include <linux/kobject.h>
111da177e4SLinus Torvalds #include <linux/string.h>
121da177e4SLinus Torvalds #include <linux/sysfs.h>
139984de1aSPaul Gortmaker #include <linux/export.h>
141da177e4SLinus Torvalds #include <linux/init.h>
15c330dda9SJeff Moyer #include <linux/kexec.h>
1622b8ce94SDave Hansen #include <linux/profile.h>
171596425fSPaul Gortmaker #include <linux/stat.h>
185cb350baSDhaval Giani #include <linux/sched.h>
19088ab0b4SLudwig Nussel #include <linux/capability.h>
2052f5684cSGideon Israel Dsouza #include <linux/compiler.h>
211da177e4SLinus Torvalds 
225a9be7c6SPaul E. McKenney #include <linux/rcupdate.h>	/* rcu_expedited and rcu_normal */
237a754743SPaul Gortmaker 
24d3d76fbdSThomas Weißschuh #if defined(__LITTLE_ENDIAN)
25d3d76fbdSThomas Weißschuh #define CPU_BYTEORDER_STRING	"little"
26d3d76fbdSThomas Weißschuh #elif defined(__BIG_ENDIAN)
27d3d76fbdSThomas Weißschuh #define CPU_BYTEORDER_STRING	"big"
28d3d76fbdSThomas Weißschuh #else
29d3d76fbdSThomas Weißschuh #error Unknown byteorder
30d3d76fbdSThomas Weißschuh #endif
31d3d76fbdSThomas Weißschuh 
321da177e4SLinus Torvalds #define KERNEL_ATTR_RO(_name) \
33386f275fSKay Sievers static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds #define KERNEL_ATTR_RW(_name) \
36a7cd9a53SMiaohe Lin static struct kobj_attribute _name##_attr = __ATTR_RW(_name)
371da177e4SLinus Torvalds 
380f76e5acSKay Sievers /* current uevent sequence number */
uevent_seqnum_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)39386f275fSKay Sievers static ssize_t uevent_seqnum_show(struct kobject *kobj,
40386f275fSKay Sievers 				  struct kobj_attribute *attr, char *buf)
411da177e4SLinus Torvalds {
429f33a88cSThomas Weißschuh 	return sysfs_emit(buf, "%llu\n", (unsigned long long)uevent_seqnum);
431da177e4SLinus Torvalds }
440f76e5acSKay Sievers KERNEL_ATTR_RO(uevent_seqnum);
450f76e5acSKay Sievers 
46d3d76fbdSThomas Weißschuh /* cpu byteorder */
cpu_byteorder_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)47d3d76fbdSThomas Weißschuh static ssize_t cpu_byteorder_show(struct kobject *kobj,
48d3d76fbdSThomas Weißschuh 				  struct kobj_attribute *attr, char *buf)
49d3d76fbdSThomas Weißschuh {
50d3d76fbdSThomas Weißschuh 	return sysfs_emit(buf, "%s\n", CPU_BYTEORDER_STRING);
51d3d76fbdSThomas Weißschuh }
52d3d76fbdSThomas Weißschuh KERNEL_ATTR_RO(cpu_byteorder);
53d3d76fbdSThomas Weißschuh 
5400142bfdSThomas Weißschuh /* address bits */
address_bits_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)5500142bfdSThomas Weißschuh static ssize_t address_bits_show(struct kobject *kobj,
5600142bfdSThomas Weißschuh 				 struct kobj_attribute *attr, char *buf)
5700142bfdSThomas Weißschuh {
5800142bfdSThomas Weißschuh 	return sysfs_emit(buf, "%zu\n", sizeof(void *) * 8 /* CHAR_BIT */);
5900142bfdSThomas Weißschuh }
6000142bfdSThomas Weißschuh KERNEL_ATTR_RO(address_bits);
6100142bfdSThomas Weißschuh 
6286d56134SMichael Marineau #ifdef CONFIG_UEVENT_HELPER
63af665852SThadeu Lima de Souza Cascardo /* uevent helper program, used during early boot */
uevent_helper_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)64386f275fSKay Sievers static ssize_t uevent_helper_show(struct kobject *kobj,
65386f275fSKay Sievers 				  struct kobj_attribute *attr, char *buf)
660f76e5acSKay Sievers {
679f33a88cSThomas Weißschuh 	return sysfs_emit(buf, "%s\n", uevent_helper);
680f76e5acSKay Sievers }
uevent_helper_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)69386f275fSKay Sievers static ssize_t uevent_helper_store(struct kobject *kobj,
70386f275fSKay Sievers 				   struct kobj_attribute *attr,
71386f275fSKay Sievers 				   const char *buf, size_t count)
720f76e5acSKay Sievers {
73312c004dSKay Sievers 	if (count+1 > UEVENT_HELPER_PATH_LEN)
740f76e5acSKay Sievers 		return -ENOENT;
75386f275fSKay Sievers 	memcpy(uevent_helper, buf, count);
76312c004dSKay Sievers 	uevent_helper[count] = '\0';
77312c004dSKay Sievers 	if (count && uevent_helper[count-1] == '\n')
78312c004dSKay Sievers 		uevent_helper[count-1] = '\0';
790f76e5acSKay Sievers 	return count;
800f76e5acSKay Sievers }
810f76e5acSKay Sievers KERNEL_ATTR_RW(uevent_helper);
8286d56134SMichael Marineau #endif
831da177e4SLinus Torvalds 
8422b8ce94SDave Hansen #ifdef CONFIG_PROFILING
profiling_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)8522b8ce94SDave Hansen static ssize_t profiling_show(struct kobject *kobj,
8622b8ce94SDave Hansen 				  struct kobj_attribute *attr, char *buf)
8722b8ce94SDave Hansen {
889f33a88cSThomas Weißschuh 	return sysfs_emit(buf, "%d\n", prof_on);
8922b8ce94SDave Hansen }
profiling_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)9022b8ce94SDave Hansen static ssize_t profiling_store(struct kobject *kobj,
9122b8ce94SDave Hansen 				   struct kobj_attribute *attr,
9222b8ce94SDave Hansen 				   const char *buf, size_t count)
9322b8ce94SDave Hansen {
9422b8ce94SDave Hansen 	int ret;
9522b8ce94SDave Hansen 
9622b8ce94SDave Hansen 	if (prof_on)
9722b8ce94SDave Hansen 		return -EEXIST;
9822b8ce94SDave Hansen 	/*
9922b8ce94SDave Hansen 	 * This eventually calls into get_option() which
10022b8ce94SDave Hansen 	 * has a ton of callers and is not const.  It is
10122b8ce94SDave Hansen 	 * easiest to cast it away here.
10222b8ce94SDave Hansen 	 */
10322b8ce94SDave Hansen 	profile_setup((char *)buf);
10422b8ce94SDave Hansen 	ret = profile_init();
10522b8ce94SDave Hansen 	if (ret)
10622b8ce94SDave Hansen 		return ret;
10722b8ce94SDave Hansen 	ret = create_proc_profile();
10822b8ce94SDave Hansen 	if (ret)
10922b8ce94SDave Hansen 		return ret;
11022b8ce94SDave Hansen 	return count;
11122b8ce94SDave Hansen }
11222b8ce94SDave Hansen KERNEL_ATTR_RW(profiling);
11322b8ce94SDave Hansen #endif
11422b8ce94SDave Hansen 
1152965faa5SDave Young #ifdef CONFIG_KEXEC_CORE
kexec_loaded_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)116386f275fSKay Sievers static ssize_t kexec_loaded_show(struct kobject *kobj,
117386f275fSKay Sievers 				 struct kobj_attribute *attr, char *buf)
118c330dda9SJeff Moyer {
1199f33a88cSThomas Weißschuh 	return sysfs_emit(buf, "%d\n", !!kexec_image);
120c330dda9SJeff Moyer }
121c330dda9SJeff Moyer KERNEL_ATTR_RO(kexec_loaded);
122c330dda9SJeff Moyer 
kexec_crash_loaded_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)123386f275fSKay Sievers static ssize_t kexec_crash_loaded_show(struct kobject *kobj,
124386f275fSKay Sievers 				       struct kobj_attribute *attr, char *buf)
125c330dda9SJeff Moyer {
1269f33a88cSThomas Weißschuh 	return sysfs_emit(buf, "%d\n", kexec_crash_loaded());
127c330dda9SJeff Moyer }
128c330dda9SJeff Moyer KERNEL_ATTR_RO(kexec_crash_loaded);
129fd59d231SKen'ichi Ohmichi 
kexec_crash_size_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)13006a7f711SAmerigo Wang static ssize_t kexec_crash_size_show(struct kobject *kobj,
13106a7f711SAmerigo Wang 				       struct kobj_attribute *attr, char *buf)
13206a7f711SAmerigo Wang {
1337bb5da0dSValentin Schneider 	ssize_t size = crash_get_memory_size();
1347bb5da0dSValentin Schneider 
1357bb5da0dSValentin Schneider 	if (size < 0)
1367bb5da0dSValentin Schneider 		return size;
1377bb5da0dSValentin Schneider 
1389f33a88cSThomas Weißschuh 	return sysfs_emit(buf, "%zd\n", size);
13906a7f711SAmerigo Wang }
kexec_crash_size_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)14006a7f711SAmerigo Wang static ssize_t kexec_crash_size_store(struct kobject *kobj,
14106a7f711SAmerigo Wang 				   struct kobj_attribute *attr,
14206a7f711SAmerigo Wang 				   const char *buf, size_t count)
14306a7f711SAmerigo Wang {
14406a7f711SAmerigo Wang 	unsigned long cnt;
14506a7f711SAmerigo Wang 	int ret;
14606a7f711SAmerigo Wang 
1476072ddc8SJingoo Han 	if (kstrtoul(buf, 0, &cnt))
14806a7f711SAmerigo Wang 		return -EINVAL;
14906a7f711SAmerigo Wang 
15006a7f711SAmerigo Wang 	ret = crash_shrink_memory(cnt);
15106a7f711SAmerigo Wang 	return ret < 0 ? ret : count;
15206a7f711SAmerigo Wang }
15306a7f711SAmerigo Wang KERNEL_ATTR_RW(kexec_crash_size);
15406a7f711SAmerigo Wang 
155692f66f2SHari Bathini #endif /* CONFIG_KEXEC_CORE */
156692f66f2SHari Bathini 
157692f66f2SHari Bathini #ifdef CONFIG_CRASH_CORE
158692f66f2SHari Bathini 
vmcoreinfo_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)159386f275fSKay Sievers static ssize_t vmcoreinfo_show(struct kobject *kobj,
160386f275fSKay Sievers 			       struct kobj_attribute *attr, char *buf)
161fd59d231SKen'ichi Ohmichi {
162dae28018SRussell King 	phys_addr_t vmcore_base = paddr_vmcoreinfo_note();
1639f33a88cSThomas Weißschuh 	return sysfs_emit(buf, "%pa %x\n", &vmcore_base,
164203e9e41SXunlei Pang 			  (unsigned int)VMCOREINFO_NOTE_SIZE);
165fd59d231SKen'ichi Ohmichi }
166fd59d231SKen'ichi Ohmichi KERNEL_ATTR_RO(vmcoreinfo);
167fd59d231SKen'ichi Ohmichi 
168*a72bbec7SEric DeVolder #ifdef CONFIG_CRASH_HOTPLUG
crash_elfcorehdr_size_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)169*a72bbec7SEric DeVolder static ssize_t crash_elfcorehdr_size_show(struct kobject *kobj,
170*a72bbec7SEric DeVolder 			       struct kobj_attribute *attr, char *buf)
171*a72bbec7SEric DeVolder {
172*a72bbec7SEric DeVolder 	unsigned int sz = crash_get_elfcorehdr_size();
173*a72bbec7SEric DeVolder 
174*a72bbec7SEric DeVolder 	return sysfs_emit(buf, "%u\n", sz);
175*a72bbec7SEric DeVolder }
176*a72bbec7SEric DeVolder KERNEL_ATTR_RO(crash_elfcorehdr_size);
177*a72bbec7SEric DeVolder 
178*a72bbec7SEric DeVolder #endif
179*a72bbec7SEric DeVolder 
180692f66f2SHari Bathini #endif /* CONFIG_CRASH_CORE */
181c330dda9SJeff Moyer 
182088ab0b4SLudwig Nussel /* whether file capabilities are enabled */
fscaps_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)183088ab0b4SLudwig Nussel static ssize_t fscaps_show(struct kobject *kobj,
184088ab0b4SLudwig Nussel 				  struct kobj_attribute *attr, char *buf)
185088ab0b4SLudwig Nussel {
1869f33a88cSThomas Weißschuh 	return sysfs_emit(buf, "%d\n", file_caps_enabled);
187088ab0b4SLudwig Nussel }
188088ab0b4SLudwig Nussel KERNEL_ATTR_RO(fscaps);
189088ab0b4SLudwig Nussel 
19079cfea02SPaul E. McKenney #ifndef CONFIG_TINY_RCU
1913705b88dSAntti P Miettinen int rcu_expedited;
rcu_expedited_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)1923705b88dSAntti P Miettinen static ssize_t rcu_expedited_show(struct kobject *kobj,
1933705b88dSAntti P Miettinen 				  struct kobj_attribute *attr, char *buf)
1943705b88dSAntti P Miettinen {
1959f33a88cSThomas Weißschuh 	return sysfs_emit(buf, "%d\n", READ_ONCE(rcu_expedited));
1963705b88dSAntti P Miettinen }
rcu_expedited_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)1973705b88dSAntti P Miettinen static ssize_t rcu_expedited_store(struct kobject *kobj,
1983705b88dSAntti P Miettinen 				   struct kobj_attribute *attr,
1993705b88dSAntti P Miettinen 				   const char *buf, size_t count)
2003705b88dSAntti P Miettinen {
2013705b88dSAntti P Miettinen 	if (kstrtoint(buf, 0, &rcu_expedited))
2023705b88dSAntti P Miettinen 		return -EINVAL;
2033705b88dSAntti P Miettinen 
2043705b88dSAntti P Miettinen 	return count;
2053705b88dSAntti P Miettinen }
2063705b88dSAntti P Miettinen KERNEL_ATTR_RW(rcu_expedited);
2073705b88dSAntti P Miettinen 
2085a9be7c6SPaul E. McKenney int rcu_normal;
rcu_normal_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)2095a9be7c6SPaul E. McKenney static ssize_t rcu_normal_show(struct kobject *kobj,
2105a9be7c6SPaul E. McKenney 			       struct kobj_attribute *attr, char *buf)
2115a9be7c6SPaul E. McKenney {
2129f33a88cSThomas Weißschuh 	return sysfs_emit(buf, "%d\n", READ_ONCE(rcu_normal));
2135a9be7c6SPaul E. McKenney }
rcu_normal_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)2145a9be7c6SPaul E. McKenney static ssize_t rcu_normal_store(struct kobject *kobj,
2155a9be7c6SPaul E. McKenney 				struct kobj_attribute *attr,
2165a9be7c6SPaul E. McKenney 				const char *buf, size_t count)
2175a9be7c6SPaul E. McKenney {
2185a9be7c6SPaul E. McKenney 	if (kstrtoint(buf, 0, &rcu_normal))
2195a9be7c6SPaul E. McKenney 		return -EINVAL;
2205a9be7c6SPaul E. McKenney 
2215a9be7c6SPaul E. McKenney 	return count;
2225a9be7c6SPaul E. McKenney }
2235a9be7c6SPaul E. McKenney KERNEL_ATTR_RW(rcu_normal);
22479cfea02SPaul E. McKenney #endif /* #ifndef CONFIG_TINY_RCU */
2255a9be7c6SPaul E. McKenney 
226da1a679cSRoland McGrath /*
227da1a679cSRoland McGrath  * Make /sys/kernel/notes give the raw contents of our kernel .notes section.
228da1a679cSRoland McGrath  */
22952f5684cSGideon Israel Dsouza extern const void __start_notes __weak;
23052f5684cSGideon Israel Dsouza extern const void __stop_notes __weak;
231da1a679cSRoland McGrath #define	notes_size (&__stop_notes - &__start_notes)
232da1a679cSRoland McGrath 
notes_read(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)2332c3c8beaSChris Wright static ssize_t notes_read(struct file *filp, struct kobject *kobj,
2342c3c8beaSChris Wright 			  struct bin_attribute *bin_attr,
235da1a679cSRoland McGrath 			  char *buf, loff_t off, size_t count)
236da1a679cSRoland McGrath {
237da1a679cSRoland McGrath 	memcpy(buf, &__start_notes + off, count);
238da1a679cSRoland McGrath 	return count;
239da1a679cSRoland McGrath }
240da1a679cSRoland McGrath 
241738bc38dSBhumika Goyal static struct bin_attribute notes_attr __ro_after_init  = {
242da1a679cSRoland McGrath 	.attr = {
243da1a679cSRoland McGrath 		.name = "notes",
244da1a679cSRoland McGrath 		.mode = S_IRUGO,
245da1a679cSRoland McGrath 	},
246da1a679cSRoland McGrath 	.read = &notes_read,
247da1a679cSRoland McGrath };
248da1a679cSRoland McGrath 
2490ff21e46SGreg Kroah-Hartman struct kobject *kernel_kobj;
2500ff21e46SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(kernel_kobj);
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds static struct attribute * kernel_attrs[] = {
253088ab0b4SLudwig Nussel 	&fscaps_attr.attr,
2540f76e5acSKay Sievers 	&uevent_seqnum_attr.attr,
255d3d76fbdSThomas Weißschuh 	&cpu_byteorder_attr.attr,
25600142bfdSThomas Weißschuh 	&address_bits_attr.attr,
25786d56134SMichael Marineau #ifdef CONFIG_UEVENT_HELPER
2580f76e5acSKay Sievers 	&uevent_helper_attr.attr,
25986d56134SMichael Marineau #endif
26022b8ce94SDave Hansen #ifdef CONFIG_PROFILING
26122b8ce94SDave Hansen 	&profiling_attr.attr,
26222b8ce94SDave Hansen #endif
2632965faa5SDave Young #ifdef CONFIG_KEXEC_CORE
264c330dda9SJeff Moyer 	&kexec_loaded_attr.attr,
265c330dda9SJeff Moyer 	&kexec_crash_loaded_attr.attr,
26606a7f711SAmerigo Wang 	&kexec_crash_size_attr.attr,
267692f66f2SHari Bathini #endif
268692f66f2SHari Bathini #ifdef CONFIG_CRASH_CORE
269fd59d231SKen'ichi Ohmichi 	&vmcoreinfo_attr.attr,
270*a72bbec7SEric DeVolder #ifdef CONFIG_CRASH_HOTPLUG
271*a72bbec7SEric DeVolder 	&crash_elfcorehdr_size_attr.attr,
272*a72bbec7SEric DeVolder #endif
273c330dda9SJeff Moyer #endif
27479cfea02SPaul E. McKenney #ifndef CONFIG_TINY_RCU
2753705b88dSAntti P Miettinen 	&rcu_expedited_attr.attr,
2765a9be7c6SPaul E. McKenney 	&rcu_normal_attr.attr,
27779cfea02SPaul E. McKenney #endif
2781da177e4SLinus Torvalds 	NULL
2791da177e4SLinus Torvalds };
2801da177e4SLinus Torvalds 
2819dcdcea1SArvind Yadav static const struct attribute_group kernel_attr_group = {
2821da177e4SLinus Torvalds 	.attrs = kernel_attrs,
2831da177e4SLinus Torvalds };
2841da177e4SLinus Torvalds 
ksysfs_init(void)2851da177e4SLinus Torvalds static int __init ksysfs_init(void)
2861da177e4SLinus Torvalds {
287bd35b93dSGreg Kroah-Hartman 	int error;
2881da177e4SLinus Torvalds 
2890ff21e46SGreg Kroah-Hartman 	kernel_kobj = kobject_create_and_add("kernel", NULL);
2900ff21e46SGreg Kroah-Hartman 	if (!kernel_kobj) {
291bd35b93dSGreg Kroah-Hartman 		error = -ENOMEM;
292bd35b93dSGreg Kroah-Hartman 		goto exit;
293bd35b93dSGreg Kroah-Hartman 	}
2940ff21e46SGreg Kroah-Hartman 	error = sysfs_create_group(kernel_kobj, &kernel_attr_group);
295bd35b93dSGreg Kroah-Hartman 	if (error)
296bd35b93dSGreg Kroah-Hartman 		goto kset_exit;
297bd35b93dSGreg Kroah-Hartman 
298bd35b93dSGreg Kroah-Hartman 	if (notes_size > 0) {
299da1a679cSRoland McGrath 		notes_attr.size = notes_size;
3000ff21e46SGreg Kroah-Hartman 		error = sysfs_create_bin_file(kernel_kobj, &notes_attr);
301bd35b93dSGreg Kroah-Hartman 		if (error)
302bd35b93dSGreg Kroah-Hartman 			goto group_exit;
303da1a679cSRoland McGrath 	}
304da1a679cSRoland McGrath 
305bd35b93dSGreg Kroah-Hartman 	return 0;
306bd35b93dSGreg Kroah-Hartman 
307bd35b93dSGreg Kroah-Hartman group_exit:
3080ff21e46SGreg Kroah-Hartman 	sysfs_remove_group(kernel_kobj, &kernel_attr_group);
309bd35b93dSGreg Kroah-Hartman kset_exit:
31078a2d906SGreg Kroah-Hartman 	kobject_put(kernel_kobj);
311bd35b93dSGreg Kroah-Hartman exit:
3121da177e4SLinus Torvalds 	return error;
3131da177e4SLinus Torvalds }
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds core_initcall(ksysfs_init);
316