mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
split kernel module api docs to README
This commit is contained in:
@@ -1,14 +1,7 @@
|
||||
= kernel_module
|
||||
|
||||
. Modules
|
||||
.. link:params.c[]
|
||||
.. link:vermagic.c[]
|
||||
.. link:vermagic_fail.c[]
|
||||
.. link:module_init.c[]
|
||||
.. link:module_info.c[]
|
||||
.. Module dependencies
|
||||
... link:dep.c[]
|
||||
... link:dep2.c[]
|
||||
Our kernel modules!
|
||||
|
||||
. Asynchronous
|
||||
.. link:irq.c[]
|
||||
.. link:schedule.c[]
|
||||
|
||||
@@ -1,76 +1,22 @@
|
||||
/*
|
||||
Exports the lkmc_dep which dep2.ko uses.
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#kernel-module-dependencies */
|
||||
|
||||
insmod /dep.ko
|
||||
# dmesg => 0
|
||||
# dmesg => 0
|
||||
# dmesg => ...
|
||||
insmod /dep2.ko
|
||||
# dmesg => 1
|
||||
# dmesg => 2
|
||||
# dmesg => ...
|
||||
rmmod dep
|
||||
# Fails because dep2 uses it.
|
||||
rmmod dep2
|
||||
# Dmesg stops incrementing.
|
||||
rmmod dep
|
||||
|
||||
sys visibility:
|
||||
|
||||
dmesg -n 1
|
||||
insmod /dep.ko
|
||||
insmod /dep2.ko
|
||||
ls -l /sys/module/dep/holders
|
||||
# => ../../dep2
|
||||
cat refcnt
|
||||
# => 1
|
||||
|
||||
proc visibility:
|
||||
|
||||
grep lkmc_dep /proc/kallsyms
|
||||
|
||||
Requires "CONFIG_KALLSYMS_ALL=y".
|
||||
|
||||
depmod:
|
||||
|
||||
grep dep "/lib/module/"*"/depmod"
|
||||
# extra/dep2.ko: extra/dep.ko
|
||||
# extra/dep.ko:
|
||||
modprobe dep
|
||||
# lsmod
|
||||
# Both dep and dep2 were loaded.
|
||||
|
||||
TODO: at what point does buildroot / busybox generate that file?
|
||||
*/
|
||||
|
||||
#include <linux/delay.h> /* usleep_range */
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
int lkmc_dep = 0;
|
||||
u32 lkmc_dep = 0;
|
||||
EXPORT_SYMBOL(lkmc_dep);
|
||||
static struct task_struct *kthread;
|
||||
|
||||
static int work_func(void *data)
|
||||
{
|
||||
while (!kthread_should_stop()) {
|
||||
pr_info("%d\n", lkmc_dep);
|
||||
usleep_range(1000000, 1000001);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static struct dentry *debugfs_file;
|
||||
|
||||
static int myinit(void)
|
||||
{
|
||||
kthread = kthread_create(work_func, NULL, "mykthread");
|
||||
wake_up_process(kthread);
|
||||
debugfs_file = debugfs_create_u32("lkmc_dep", S_IRUSR | S_IWUSR, NULL, &lkmc_dep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void myexit(void)
|
||||
{
|
||||
kthread_stop(kthread);
|
||||
debugfs_remove(debugfs_file);
|
||||
}
|
||||
|
||||
module_init(myinit)
|
||||
|
||||
@@ -1,30 +1,21 @@
|
||||
#include <linux/delay.h> /* usleep_range */
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#kernel-module-dependencies */
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
extern int lkmc_dep;
|
||||
static struct task_struct *kthread;
|
||||
|
||||
static int work_func(void *data)
|
||||
{
|
||||
while (!kthread_should_stop()) {
|
||||
usleep_range(1000000, 1000001);
|
||||
lkmc_dep++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
extern u32 lkmc_dep;
|
||||
static struct dentry *debugfs_file;
|
||||
|
||||
static int myinit(void)
|
||||
{
|
||||
kthread = kthread_create(work_func, NULL, "mykthread");
|
||||
wake_up_process(kthread);
|
||||
debugfs_file = debugfs_create_u32("lkmc_dep2", S_IRUSR | S_IWUSR, NULL, &lkmc_dep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void myexit(void)
|
||||
{
|
||||
kthread_stop(kthread);
|
||||
debugfs_remove(debugfs_file);
|
||||
}
|
||||
|
||||
module_init(myinit)
|
||||
|
||||
16
kernel_module/init_module.c
Normal file
16
kernel_module/init_module.c
Normal file
@@ -0,0 +1,16 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#init_module */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
pr_info("init_module\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_module(void)
|
||||
{
|
||||
pr_info("cleanup_module\n");
|
||||
}
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1,17 +1,4 @@
|
||||
/*
|
||||
- https://stackoverflow.com/questions/4839024/how-to-find-the-version-of-a-compiled-kernel-module/42556565#42556565
|
||||
- https://stackoverflow.com/questions/19467150/significance-of-this-module-in-linux-driver/49812248#49812248
|
||||
|
||||
Usage:
|
||||
|
||||
insmod /module_info.ko
|
||||
# dmesg => name = module_info
|
||||
# dmesg => version = 1.0
|
||||
cat /sys/module/module_info/version
|
||||
# => module_info
|
||||
modinfo /module_info.ko | grep -E '^version:'
|
||||
# => version: 1.0
|
||||
*/
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#module_info */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -19,8 +6,10 @@ Usage:
|
||||
static int myinit(void)
|
||||
{
|
||||
/* Set by default based on the module file name. */
|
||||
pr_info("name = %s\n", THIS_MODULE->name);
|
||||
pr_info("name = %s\n", THIS_MODULE->name);
|
||||
pr_info("version = %s\n", THIS_MODULE->version);
|
||||
/* ERROR: nope, not part of struct module. */
|
||||
/*pr_info("asdf = %s\n", THIS_MODULE->asdf);*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -28,5 +17,6 @@ static void myexit(void) {}
|
||||
|
||||
module_init(myinit)
|
||||
module_exit(myexit)
|
||||
MODULE_INFO(asdf, "qwer");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
https://stackoverflow.com/questions/3218320/what-is-the-difference-between-module-init-and-init-module-in-a-linux-kernel-mod
|
||||
|
||||
Hello world with direct init_module and cleantup_module.
|
||||
|
||||
This appears to be an older method that still works but has some drawbacks.
|
||||
|
||||
vs module_init and module_exit?
|
||||
|
||||
- modprobe only works with the module_init / module_exit. Try "modprobe module_init".
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
pr_info("init_module\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_module(void)
|
||||
{
|
||||
pr_info("cleanup_module\n");
|
||||
}
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1,68 +1,53 @@
|
||||
/*
|
||||
Allows passing parameters at insertion time.
|
||||
|
||||
Those parameters can also be read and modified at runtime from /sys.
|
||||
|
||||
insmod /params.ko
|
||||
# dmesg => 0 0
|
||||
cd /sys/module/params/parameters
|
||||
cat i
|
||||
# => 1 0
|
||||
printf 1 >i
|
||||
# dmesg => 1 0
|
||||
rmmod params
|
||||
|
||||
insmod /params.ko i=1 j=1
|
||||
# dmesg => 1 1
|
||||
rmmod params
|
||||
|
||||
modinfo
|
||||
/params.ko
|
||||
# Output contains MODULE_PARAM_DESC descriptions.
|
||||
|
||||
modprobe insertion can also set default parameters via the /etc/modprobe.conf file. So:
|
||||
|
||||
modprobe params
|
||||
|
||||
Outputs:
|
||||
|
||||
12 34
|
||||
*/
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#kernel-module-parameters */
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h> /* usleep_range */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/seq_file.h> /* seq_read, seq_lseek, single_release */
|
||||
#include <uapi/linux/stat.h> /* S_IRUSR | S_IWUSR */
|
||||
|
||||
static int i = 0;
|
||||
static int j = 0;
|
||||
static u32 i = 0;
|
||||
static u32 j = 0;
|
||||
module_param(i, int, S_IRUSR | S_IWUSR);
|
||||
module_param(j, int, S_IRUSR | S_IWUSR);
|
||||
MODULE_PARM_DESC(i, "my favorite int");
|
||||
MODULE_PARM_DESC(j, "my second favorite int");
|
||||
|
||||
static struct task_struct *kthread;
|
||||
static struct dentry *debugfs_file;
|
||||
|
||||
static int work_func(void *data)
|
||||
static int show(struct seq_file *m, void *v)
|
||||
{
|
||||
while (!kthread_should_stop()) {
|
||||
pr_info("%d %d\n", i, j);
|
||||
usleep_range(1000000, 1000001);
|
||||
}
|
||||
char kbuf[18];
|
||||
int ret;
|
||||
|
||||
ret = snprintf(kbuf, sizeof(kbuf), "%d %d", i, j);
|
||||
seq_printf(m, kbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, show, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations fops = {
|
||||
.llseek = seq_lseek,
|
||||
.open = open,
|
||||
.owner = THIS_MODULE,
|
||||
.read = seq_read,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int myinit(void)
|
||||
{
|
||||
kthread = kthread_create(work_func, NULL, "mykthread");
|
||||
wake_up_process(kthread);
|
||||
debugfs_file = debugfs_create_file("lkmc_params", S_IRUSR, NULL, NULL, &fops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void myexit(void)
|
||||
{
|
||||
kthread_stop(kthread);
|
||||
debugfs_remove(debugfs_file);
|
||||
}
|
||||
|
||||
module_init(myinit)
|
||||
|
||||
@@ -23,8 +23,3 @@ These programs can also be compiled and used on host.
|
||||
.. x86_64
|
||||
... link:rdtsc.c[]
|
||||
... link:ring0.c[]
|
||||
. Module tests
|
||||
.. link:anonymous_inode.c[]
|
||||
.. link:ioctl.c[]
|
||||
.. link:netlink.c[]
|
||||
.. link:poll.c[]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#kernel-module-parameters#myinsmod */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
/*
|
||||
insmod /vermagic.ko
|
||||
# => 4.9.6 SMP mod_unload modversions
|
||||
|
||||
TODO how to get the vermagic from running kernel from userland?
|
||||
<https://lists.kernelnewbies.org/pipermail/kernelnewbies/2012-October/006306.html>
|
||||
*/
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#vermagic */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -12,7 +6,9 @@ TODO how to get the vermagic from running kernel from userland?
|
||||
|
||||
static int myinit(void)
|
||||
{
|
||||
pr_info(__FILE__ "\n");
|
||||
pr_info("VERMAGIC_STRING = " VERMAGIC_STRING "\n");
|
||||
/* Nice try, but it is not a member. */
|
||||
/*pr_info("THIS_MODULE->vermagic = %s\n", THIS_MODULE->vermagic);*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,4 @@
|
||||
/*
|
||||
insmod /vermagic_fail.ko
|
||||
# => insmod: can't insert '/vermagic_fail.ko': invalid module format
|
||||
|
||||
modinfo /vermagic_fail.ko | grep vermagic
|
||||
# => vermagic: asdfqwer
|
||||
# => vermagic: 4.9.6 SMP mod_unload modversions
|
||||
|
||||
kmod `modprobe` has a flag to skip the check:
|
||||
|
||||
--force-modversion
|
||||
|
||||
Looks like it just strips `modversion` information from the module before loading, and then the kernel skips the check.
|
||||
*/
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#vermagic */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
Reference in New Issue
Block a user