summaryrefslogtreecommitdiff
path: root/md/notes/kernel/create_sysfs_entry.md
diff options
context:
space:
mode:
Diffstat (limited to 'md/notes/kernel/create_sysfs_entry.md')
-rw-r--r--md/notes/kernel/create_sysfs_entry.md247
1 files changed, 246 insertions, 1 deletions
diff --git a/md/notes/kernel/create_sysfs_entry.md b/md/notes/kernel/create_sysfs_entry.md
index 2af3cca..529930a 100644
--- a/md/notes/kernel/create_sysfs_entry.md
+++ b/md/notes/kernel/create_sysfs_entry.md
@@ -5,6 +5,250 @@ keywords:kernel,linux,threads
## Starting point
+__Makefile__
+```Makefile
+obj-m += sysfs_entry.o
+
+KDIR ?= /lib/modules/$(shell uname -r)/build
+
+all:
+ make -C $(KDIR) M=$(PWD) modules
+
+clean:
+ make -C $(KDIR) M=$(PWD) clean
+```
+
+__sysfs_entry.c__
+```c
+#include <linux/module.h> /* Needed by all modules */
+#include <linux/kernel.h>
+
+int sysfs_entry_init( void )
+{
+ printk(KERN_DEBUG "Hello Sysfs!\n");
+ return 0;
+}
+
+void sysfs_entry_exit( void )
+{
+ printk(KERN_DEBUG "Exit Sysfs!\n");
+}
+
+module_init( sysfs_entry_init );
+module_exit( sysfs_entry_exit );
+
+MODULE_LICENSE("GPL");
+```
+
+## Creating entries
+
+### Kobject structure
+
+```c
+struct kobject {
+ const char *name;
+ struct list_head entry;
+ struct kobject *parent;
+ struct kset *kset;
+ const struct kobj_type *ktype;
+ struct kernfs_node *sd; /* sysfs directory entry */
+ struct kref kref;
+#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
+ struct delayed_work release;
+#endif
+ unsigned int state_initialized:1;
+ unsigned int state_in_sysfs:1;
+ unsigned int state_add_uevent_sent:1;
+ unsigned int state_remove_uevent_sent:1;
+ unsigned int uevent_suppress:1;
+};
+```
+
+### Add entry to /sys/kernel
+
+__sysfs_entry.c__
+```c
+struct kobject *sysfs_kobj;
+
+int sysfs_entry_init( void )
+{
+ ...
+
+ sysfs_kobj = kobject_create_and_add("secret", kernel_kobj);
+
+ ...
+ return 0;
+}
+
+void sysfs_entry_exit( void )
+{
+ ...
+
+ kobject_put(sysfs_kobj);
+}
+
+```
+
+When loading module with
+```sh
+sudo insmod sysfs_entry.ko
+```
+
+There should be new directory under /sys/kernel called secret.
+
+### Add file under the directory
+
+__sysfs_entry.c__
+```c
+
+...
+volatile int secret_value;
+
+struct kobject *sysfs_kobj;
+struct kobj_attribute secret_attr = __ATTR(secret_value, 0660, NULL, NULL);
+...
+
+int sysfs_entry_init( void )
+{
+ ...
+
+ if(sysfs_create_file(sysfs_kobj, &secret_attr.attr)) {
+ pr_err("Cant create secret file");
+ }
+
+
+ ...
+ return 0;
+}
+
+void sysfs_entry_exit( void )
+{
+ ...
+ sysfs_remove_file(sysfs_kobj, &secret_attr.attr);
+ ...
+
+}
+```
+
+Now we are able to find secret_value file and attempt to read values
+
+```sh
+sudo cat /sys/kernel/secret/secret_value
+cat: /sys/kernel/secret/secret_value: Input/output error
+```
+
+### Read write value from the syfs entry
+
+__sysfs_entry.c__
+```c
+...
+static ssize_t secret_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) {
+ printk(KERN_DEBUG "Show value %d\n", secret_value);
+ return sprintf(buf, "%d", secret_value);
+}
+
+static ssize_t secret_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t count) {
+ printk(KERN_DEBUG "Set value %s %ldd\n", buf, count);
+ sscanf(buf, "%d", &secret_value);
+ return count;
+}
+
+struct kobj_attribute secret_attr = __ATTR(secret_value, 0660, secret_show, secret_store);
+...
+
+int sysfs_entry_init( void )
+{
+ ...
+
+ ...
+ return 0;
+}
+
+void sysfs_entry_exit( void )
+{
+ ...
+ sysfs_remove_file(sysfs_kobj, &secret_attr.attr);
+ kobject_put(sysfs_kobj);
+ ...
+}
+```
+
+Now we are able to set and read values from sys file
+
+
+```sh
+sudo cat /sys/kernel/secret/secret_value
+```
+or
+```sh
+echo 1 | sudo tee -a /sys/kernel/secret/secret_value
+```
+
+## List of functions used
+
+| Function name | Note |
+|---|---|
+| kobject_create_and_add | |
+| sysfs_create_file | |
+| sysfs_remove_file | |
+| kobject_put | |
+| | |
+
+
+
+## Final result
+
+__sysfs_entry.c__
+```c
+#include <linux/module.h> /* Needed by all modules */
+#include <linux/kernel.h>
+
+volatile int secret_value;
+
+struct kobject *sysfs_kobj;
+
+static ssize_t secret_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) {
+ printk(KERN_DEBUG "Show value %d\n", secret_value);
+ return sprintf(buf, "%d", secret_value);
+}
+
+
+static ssize_t secret_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t count) {
+ printk(KERN_DEBUG "Set value %s %ldd\n", buf, count);
+ sscanf(buf, "%d", &secret_value);
+ return count;
+}
+
+struct kobj_attribute secret_attr = __ATTR(secret_value, 0660, secret_show, secret_store);
+
+
+int sysfs_entry_init( void )
+{
+ printk(KERN_DEBUG "Hello Syscfs!\n");
+
+ sysfs_kobj = kobject_create_and_add("secret", kernel_kobj);
+
+ if(sysfs_create_file(sysfs_kobj, &secret_attr.attr)) {
+ pr_err("Cant create secret file");
+ }
+
+ return 0;
+}
+
+void sysfs_entry_exit( void )
+{
+ printk(KERN_DEBUG "Exit Sysfs!\n");
+
+ sysfs_remove_file(sysfs_kobj, &secret_attr.attr);
+ kobject_put(sysfs_kobj);
+}
+
+module_init( sysfs_entry_init );
+module_exit( sysfs_entry_exit );
+
+MODULE_LICENSE("GPL");
+
+```
## Links
@@ -12,5 +256,6 @@ https://man7.org/linux/man-pages/man5/sysfs.5.html
https://embetronicx.com/tutorials/linux/device-drivers/sysfs-in-linux-kernel/
https://elixir.bootlin.com/linux/v6.1.64/source/include/linux/sysfs.h
https://docs.kernel.org/filesystems/sysfs.html
-
+https://elixir.bootlin.com/linux/v6.1.64/source/include/linux/kobject.h#L64
+https://pradheepshrinivasan.github.io/2015/07/02/Creating-an-simple-sysfs/