My Tutorials/Writing Linux kernel modules
From ThorstensHome
(Redirected from Writing Linux kernel modules)
Contents |
Keyboard wire watcher
This kernel module watches, after it is loaded, for some seconds what comes from the keyboard and displays this.
keyb.c
/* A kernel module.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <asm/io.h>
int init_module(void)
{
printk("This is a kernel module\n");
int retries = 0x100100;
int input;
while (--retries != 0)
{
int oldinput=input; input=inb(0x60); if (oldinput!=input)
{
printk("got %i",input);
// print directly to konsole
// kernel 2.6.9+ required
char *str="hello";
sprintf(str,"%i",input);
struct tty_struct *my_tty;
my_tty = current->signal->tty;
if (my_tty != NULL)
{
((my_tty->driver)->write) (my_tty,str,strlen(str));
((my_tty->driver)->write) (my_tty,"\015\012",2);
}
}
}
}
void cleanup_module(void)
{
printk(KERN_ALERT "Au revoir\n");
}
Makefile
obj-m += keyb.o
How to compile Do not change directory and issue:
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
How to use
insmod keyb
Get rid of it
rmmod keyb
Understanding modinfo
tweedleburg:~/mod # modinfo keyb.ko filename: keyb.ko srcversion: 284786FFEC172AAD1E91C48 depends: vermagic: 2.6.25.9-0.2-default SMP mod_unload tweedleburg:~/mod # strings keyb.ko ATSH Z[A\A] <1>Au revoir This is a kernel module got %i hello srcversion=284786FFEC172AAD1E91C48 depends= vermagic=2.6.25.9-0.2-default SMP mod_unload keyb tweedleburg:~/mod #
functions
Inside a kernel module, you can call all functions from /proc/kallsyms, including printk and panic("test").
Interrupts
You will only be able to free irqs that are to be found in /proc/interrupts.
Keyboard driver
Here's the first keyboard driver I wrote.
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#include <asm/io.h>
#define NAME "inter.c"
static struct workqueue_struct *mqueue;
static void char2(void *scancode)
{
int iscancode = (int)*((char *) scancode );
printk(KERN_INFO "%i",iscancode);
if ( ((int)*((char *)scancode)) == 38 ) panic("pan38");
}
irqreturn_t irqhandler(int irq, void *dev_id, struct pt_regs *regs)
{
static int initialised = 0;
static unsigned char scancode;
static struct work_struct task;
unsigned char state;
state = inb(0x64);
scancode = inb(0x60);
if (initialised == 0)
{
INIT_WORK(&task, char2, &scancode);
initialised = 1;
}
else
{
PREPARE_WORK(&task, char2, &scancode);
}
queue_work(mqueue, &task);
return IRQ_HANDLED;
}
int init_module()
{
mqueue = create_workqueue(NAME);
free_irq(1, NULL);
return request_irq(1,irqhandler, SA_SHIRQ, "kbd", (void *)(irqhandler));
}
void cleanup_module()
{
free_irq(1, NULL);
}
MODULE_LICENSE("GPL");
TimeSetter
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#include <asm/io.h>
#include <linux/reboot.h>
#include <linux/syscalls.h>
#include <linux/time.h>
#define NAME "inter.c"
static struct workqueue_struct *mqueue;
irqreturn_t irqhandler(int irq, void *dev_id, struct pt_regs *regs)
{
printk("h");
return IRQ_HANDLED;
}
int init_module()
{
struct timespec* t;
do_settimeofday(t);
}
void cleanup_module()
{
}
MODULE_LICENSE("GPL");
Uptime counter
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#include <asm/io.h>
#include <linux/reboot.h>
#include <linux/syscalls.h>
#include <linux/time.h>
#include <linux/sched.h>
#define NAME "inter.c"
int init_module()
{
printk("Your kernel HZ values is %i\n", HZ);
printk("Since start or overflow, %i ticks have been gone", jiffies);
}
void cleanup_module()
{
}
MODULE_LICENSE("GPL");
Key simulator
/*
* Simulate a keypress
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/version.h>
#include <linux/keyboard.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/tty_flip.h>
#include <linux/tty.h>
#include <linux/string.h>
#include <linux/tty_flip.h>
#include <linux/mm.h>
#include <linux/irq.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/vt_kern.h>
#include <linux/sysrq.h>
#include <linux/kbd_kern.h>
#include <linux/kbd_diacr.h>
#include <linux/input.h>
#include <linux/reboot.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thorsten Staerk");
struct tty_struct *tty;
int ch;
static void println(char *string)
{
tty = current->signal->tty;
(tty->driver)->write (tty, string, strlen(string));
((tty->driver)->write) (tty, "\015\012", 2);
}
static int __init print_string_init(void)
{
println("Simulating the keypress of an A");
ch=65;
tty_insert_flip_char(tty, ch, 0);
con_schedule_flip(tty);
return 0;
}
static void __exit print_string_exit(void)
{
println("Hasta la vista");
}
module_init(print_string_init);
module_exit(print_string_exit);
Memory reader
This reads memory address 0x100 and writes into the dmesg-syslog.
#include <linux/module.h>
#define NAME "inter.c"
int init_module()
{
int i=0x100;
printk("i is at address %i; ",i);
printk("i is %i",&i);
return 0;
}
void cleanup_module()
{
}
MODULE_LICENSE("GPL");
reboot
Sometimes you need to trigger a reboot with your kernel module, e.g. if you want to write a keyboard driver and have a reset-key handy. This module does nothing but trigger a reboot:
#include <linux/module.h>
#include <linux/reboot.h>
#define NAME "inter4.c"
int init_module()
{
emergency_restart();
return 0;
}
void cleanup_module()
{
}
MODULE_LICENSE("GPL");
See also
- http://tldp.org/LDP/lkmpg/2.6/html/
- http://www.xml.com/ldd/chapter/book/ch06.html#t1 (jiffies)
- http://kernelnewbies.org/Drivers
- http://ezs.kr.hsnr.de/TreiberBuch/html/ (complete book in german)