mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
Use module_init, mention modprobe on readme
This commit is contained in:
@@ -41,6 +41,14 @@ After the first build, you can also run just:
|
|||||||
|
|
||||||
to save a few seconds. `./run` wouldn't rebuild everything, but checking timestamps takes a few moments.
|
to save a few seconds. `./run` wouldn't rebuild everything, but checking timestamps takes a few moments.
|
||||||
|
|
||||||
|
If you are feeling fancy, you can also insert modules with:
|
||||||
|
|
||||||
|
modprobe hello
|
||||||
|
|
||||||
|
and if you are feeling raw, you can use:
|
||||||
|
|
||||||
|
/myinsmod.out /hello.ko
|
||||||
|
|
||||||
We use `printk` a lot, and it shows on the QEMU terminal by default. If that annoys you (e.g. you want to see stdout separately), do:
|
We use `printk` a lot, and it shows on the QEMU terminal by default. If that annoys you (e.g. you want to see stdout separately), do:
|
||||||
|
|
||||||
dmesg -n 1
|
dmesg -n 1
|
||||||
@@ -299,6 +307,7 @@ But TODO I don't think you can see where you are in the kernel source code and l
|
|||||||
1. [Introduction](introduction.md)
|
1. [Introduction](introduction.md)
|
||||||
1. [Build](build.md)
|
1. [Build](build.md)
|
||||||
1. [kmod](kmod.md)
|
1. [kmod](kmod.md)
|
||||||
|
1. []
|
||||||
1. [Bibliography](bibliography.md)
|
1. [Bibliography](bibliography.md)
|
||||||
1. Examples
|
1. Examples
|
||||||
1. [Host](host/)
|
1. [Host](host/)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ MODULE_LICENSE("GPL");
|
|||||||
static struct dentry *dir;
|
static struct dentry *dir;
|
||||||
static u32 value = 42;
|
static u32 value = 42;
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
struct dentry *file;
|
struct dentry *file;
|
||||||
dir = debugfs_create_dir("lkmc_debugfs", 0);
|
dir = debugfs_create_dir("lkmc_debugfs", 0);
|
||||||
@@ -33,7 +33,10 @@ int init_module(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
debugfs_remove_recursive(dir);
|
debugfs_remove_recursive(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ static const struct file_operations fops = {
|
|||||||
.write = fop_write,
|
.write = fop_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
struct dentry *file;
|
struct dentry *file;
|
||||||
dir = debugfs_create_dir("lkmc_fops", 0);
|
dir = debugfs_create_dir("lkmc_fops", 0);
|
||||||
@@ -152,7 +152,10 @@ int init_module(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
debugfs_remove_recursive(dir);
|
debugfs_remove_recursive(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Hello world module.
|
|||||||
insmod hello.ko
|
insmod hello.ko
|
||||||
dmesg -c | grep 'hello init'
|
dmesg -c | grep 'hello init'
|
||||||
rmmod hello.ko
|
rmmod hello.ko
|
||||||
dmesg -c | grep 'hello cleanup'
|
dmesg -c | grep 'hello exit'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
@@ -13,13 +13,16 @@ Hello world module.
|
|||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
printk(KERN_INFO "hello init\n");
|
printk(KERN_INFO "hello init\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
printk(KERN_INFO "hello cleanup\n");
|
printk(KERN_INFO "hello exit\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -9,13 +9,16 @@ Mostly to check that our build infrastructure can handle more than one module!
|
|||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
printk(KERN_INFO "hello2 init\n");
|
printk(KERN_INFO "hello2 init\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
printk(KERN_INFO "hello2 cleanup\n");
|
printk(KERN_INFO "hello2 exit\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ static irqreturn_t handler(int i, void *v)
|
|||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
irqreturn_t r;
|
irqreturn_t r;
|
||||||
r = request_irq(
|
r = request_irq(
|
||||||
@@ -37,6 +37,9 @@ int init_module(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -31,15 +31,18 @@ static int work_func(void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
kthread = kthread_create(work_func, NULL, "mykthread");
|
kthread = kthread_create(work_func, NULL, "mykthread");
|
||||||
wake_up_process(kthread);
|
wake_up_process(kthread);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
/* Waits for thread to return. */
|
/* Waits for thread to return. */
|
||||||
kthread_stop(kthread);
|
kthread_stop(kthread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ static int work_func2(void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
kthread1 = kthread_create(work_func1, NULL, "mykthread1");
|
kthread1 = kthread_create(work_func1, NULL, "mykthread1");
|
||||||
kthread2 = kthread_create(work_func2, NULL, "mykthread2");
|
kthread2 = kthread_create(work_func2, NULL, "mykthread2");
|
||||||
@@ -46,8 +46,11 @@ int init_module(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
kthread_stop(kthread1);
|
kthread_stop(kthread1);
|
||||||
kthread_stop(kthread2);
|
kthread_stop(kthread2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
/*
|
/*
|
||||||
Hello world with module_init / exit macros.
|
https://stackoverflow.com/questions/3218320/what-is-the-difference-between-module-init-and-init-module-in-a-linux-kernel-mod
|
||||||
|
|
||||||
TODO: vs direct init_module and cleanup_module.
|
Hello world with direct init_module and cleantup_module.
|
||||||
|
|
||||||
- modprobe only works with the macros. Try "modprobe module_init".
|
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/module.h>
|
||||||
@@ -11,16 +15,13 @@ TODO: vs direct init_module and cleanup_module.
|
|||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
static int module_init_init(void)
|
int init_module(void)
|
||||||
{
|
{
|
||||||
pr_info("module_init init\n");
|
printk(KERN_INFO "init_module\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void module_init_exit(void)
|
void cleanup_module(void)
|
||||||
{
|
{
|
||||||
pr_info("module_exit cleanup\n");
|
printk(KERN_INFO "cleanup_module\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(module_init_init)
|
|
||||||
module_exit(module_init_exit)
|
|
||||||
|
|||||||
@@ -13,14 +13,17 @@ The alternative is to get the serial data out streamed to console or to a file:
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
printk(KERN_INFO "panic init\n");
|
printk(KERN_INFO "panic init\n");
|
||||||
panic("hello panic");
|
panic("hello panic");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
printk(KERN_INFO "panic cleanup\n");
|
printk(KERN_INFO "panic cleanup\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -47,14 +47,17 @@ static int work_func(void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
kthread = kthread_create(work_func, NULL, "mykthread");
|
kthread = kthread_create(work_func, NULL, "mykthread");
|
||||||
wake_up_process(kthread);
|
wake_up_process(kthread);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
kthread_stop(kthread);
|
kthread_stop(kthread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ static const struct file_operations fops = {
|
|||||||
.poll = poll
|
.poll = poll
|
||||||
};
|
};
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
dir = debugfs_create_dir("lkmc_poll", 0);
|
dir = debugfs_create_dir("lkmc_poll", 0);
|
||||||
debugfs_create_file("f", 0666, dir, NULL, &fops);
|
debugfs_create_file("f", 0666, dir, NULL, &fops);
|
||||||
@@ -70,7 +70,10 @@ int init_module(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
debugfs_remove_recursive(dir);
|
debugfs_remove_recursive(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ kthreads only allow interrupting if you call schedule.
|
|||||||
|
|
||||||
If you don't, they just run forever, and you have to kill the VM.
|
If you don't, they just run forever, and you have to kill the VM.
|
||||||
|
|
||||||
|
Sleep functions like usleep_range also end up calling schedule.
|
||||||
|
|
||||||
Test with:
|
Test with:
|
||||||
|
|
||||||
dmesg -n 1
|
dmesg -n 1
|
||||||
@@ -19,7 +21,6 @@ Then:
|
|||||||
- yn=1: all good
|
- yn=1: all good
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/delay.h> /* usleep_range */
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
@@ -45,14 +46,17 @@ static int work_func(void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
kthread = kthread_create(work_func, NULL, "mykthread");
|
kthread = kthread_create(work_func, NULL, "mykthread");
|
||||||
wake_up_process(kthread);
|
wake_up_process(kthread);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
kthread_stop(kthread);
|
kthread_stop(kthread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ static void work_func(struct work_struct *work)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
DECLARE_WORK(work, work_func);
|
DECLARE_WORK(work, work_func);
|
||||||
queue = create_workqueue("myworkqueue");
|
queue = create_workqueue("myworkqueue");
|
||||||
@@ -40,8 +40,11 @@ int init_module(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
atomic_set(&run, 0);
|
atomic_set(&run, 0);
|
||||||
destroy_workqueue(queue);
|
destroy_workqueue(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -28,14 +28,17 @@ static void callback(unsigned long data)
|
|||||||
mod_timer(&mytimer, jiffies + onesec);
|
mod_timer(&mytimer, jiffies + onesec);
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
onesec = msecs_to_jiffies(1000);
|
onesec = msecs_to_jiffies(1000);
|
||||||
mod_timer(&mytimer, jiffies + onesec);
|
mod_timer(&mytimer, jiffies + onesec);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
del_timer(&mytimer);
|
del_timer(&mytimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ static int kthread_func2(void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
init_waitqueue_head(&queue);
|
init_waitqueue_head(&queue);
|
||||||
kthread1 = kthread_create(kthread_func1, NULL, "mykthread1");
|
kthread1 = kthread_create(kthread_func1, NULL, "mykthread1");
|
||||||
@@ -56,8 +56,11 @@ int init_module(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
kthread_stop(kthread1);
|
kthread_stop(kthread1);
|
||||||
kthread_stop(kthread2);
|
kthread_stop(kthread2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ static void work_func(struct work_struct *work)
|
|||||||
queue_delayed_work(queue, &next_work, HZ);
|
queue_delayed_work(queue, &next_work, HZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
DECLARE_WORK(work, work_func);
|
DECLARE_WORK(work, work_func);
|
||||||
queue = create_workqueue("myworkqueue");
|
queue = create_workqueue("myworkqueue");
|
||||||
@@ -29,7 +29,10 @@ int init_module(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
destroy_workqueue(queue);
|
destroy_workqueue(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
@@ -32,15 +32,18 @@ static void work_func(struct work_struct *work)
|
|||||||
|
|
||||||
DECLARE_WORK(work, work_func);
|
DECLARE_WORK(work, work_func);
|
||||||
|
|
||||||
int init_module(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
queue = create_singlethread_workqueue("myworkqueue");
|
queue = create_singlethread_workqueue("myworkqueue");
|
||||||
queue_work(queue, &work);
|
queue_work(queue, &work);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_module(void)
|
static void myexit(void)
|
||||||
{
|
{
|
||||||
/* Waits for jobs to finish. */
|
/* Waits for jobs to finish. */
|
||||||
destroy_workqueue(queue);
|
destroy_workqueue(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module_init(myinit)
|
||||||
|
module_exit(myexit)
|
||||||
|
|||||||
13
kmod.md
13
kmod.md
@@ -1,6 +1,10 @@
|
|||||||
# kmod
|
# kmod
|
||||||
|
|
||||||
Implements `lsmod`, `insmod`, `rmmod`, and other tools.
|
Multi-call executable that implements: `lsmod`, `insmod`, `rmmod`, and other tools.
|
||||||
|
|
||||||
|
BusyBox also implements its own version of those executables.
|
||||||
|
|
||||||
|
Source: <https://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git>
|
||||||
|
|
||||||
The other tools are just symlinks to it.
|
The other tools are just symlinks to it.
|
||||||
|
|
||||||
@@ -77,7 +81,12 @@ Remove a module. Takes either the module name or the `.ko` file:
|
|||||||
|
|
||||||
## modprobe
|
## modprobe
|
||||||
|
|
||||||
List available modules relative path to `/lib/modules/VERSION/`:
|
Vs `insmod`:
|
||||||
|
|
||||||
|
- <https://askubuntu.com/questions/20070/whats-the-difference-between-insmod-and-modprobe>
|
||||||
|
- <https://stackoverflow.com/questions/22891705/whats-the-difference-between-insmod-and-modprobe>
|
||||||
|
|
||||||
|
List available modules relative path to `/lib/modules/$KERNEL_VERSION/`:
|
||||||
|
|
||||||
sudo modprobe -l
|
sudo modprobe -l
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user