Difference between revisions of "My Tutorials/Writing Linux kernel modules"

From ThorstensHome
Jump to: navigation, search
m (1 revision(s))
(wait a second)
 
(15 intermediate revisions by one user not shown)
Line 1: Line 1:
== Keyboard wire watcher ==
+
{{DISPLAYTITLE:Writing Linux kernel modules}}
  
This kernel module watches, after it is loaded, for some seconds what comes from the keyboard and displays this.
+
= wait a second =
 +
This kernel module waits a second when it is initialized. You can modify it and use it e.g. to print the bytes coming from your keyboard for one second.
 +
 
 +
== the source code ==
 +
'''driver.c'''
 +
<pre>
 +
#include <linux/module.h>
 +
 
 +
int init_module()
 +
{
 +
  printk("Starting driver...");
 +
  unsigned long j;
 +
  j=jiffies;
 +
  while (jiffies-j<=HZ)
 +
  {}
 +
  printk("done\n");
 +
  return 0;
 +
}
 +
 +
void cleanup_module()
 +
{
 +
}
 +
MODULE_LICENSE("GPL");
 +
</pre>
 +
 
 +
'''Makefile'''
 +
obj-m += driver.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.ko
 +
 
 +
== Get rid of it ==
 +
rmmod keyb
 +
 
 +
== Understanding modinfo ==
 +
<pre>
 +
# modinfo driver.ko
 +
filename:      driver.ko
 +
license:        GPL
 +
srcversion:    CEF3E0AB0FE04A24F00B7A6
 +
depends:       
 +
vermagic:      3.1.10-1.16-desktop SMP preempt mod_unload modversions
 +
# strings driver.ko
 +
Starting driver...
 +
done
 +
license=GPL
 +
srcversion=CEF3E0AB0FE04A24F00B7A6
 +
depends=
 +
vermagic=3.1.10-1.16-desktop SMP preempt mod_unload modversions
 +
module_layout
 +
jiffies
 +
printk
 +
driver
 +
</pre>
 +
 
 +
= Keyboard wire watcher =
 +
This kernel module watches, after it is loaded, for some seconds what comes from the keyboard and displays this. You will need a PS/2 keyboard, not a USB one. It works with Linux 2.6.9 kernels and higher.
  
 
'''keyb.c'''
 
'''keyb.c'''
Line 35: Line 95:
 
       if (my_tty != NULL)
 
       if (my_tty != NULL)
 
       {
 
       {
         ((my_tty->driver)->write) (my_tty,str,strlen(str));
+
         ((my_tty->driver)->ops->write) (my_tty,str,strlen(str));
         ((my_tty->driver)->write) (my_tty,"\015\012",2);
+
         ((my_tty->driver)->ops->write) (my_tty,"\015\012",2);
 
       }
 
       }
 
     }
 
     }
Line 78: Line 138:
 
</pre>
 
</pre>
  
== functions ==
+
= functions =
  
 
Inside a kernel module, you can call all functions from /proc/kallsyms, including printk and panic("test").
 
Inside a kernel module, you can call all functions from /proc/kallsyms, including printk and panic("test").
  
== Interrupts ==
+
= Interrupts =
  
 
You will only be able to free irqs that are to be found in /proc/interrupts.
 
You will only be able to free irqs that are to be found in /proc/interrupts.
  
== Keyboard driver ==
+
= Keyboard driver =
  
 
Here's the first keyboard driver I wrote.
 
Here's the first keyboard driver I wrote.
Line 145: Line 205:
 
  MODULE_LICENSE("GPL");
 
  MODULE_LICENSE("GPL");
  
== TimeSetter ==
+
= TimeSetter =
 
  #include <linux/module.h>
 
  #include <linux/module.h>
 
  #include <linux/interrupt.h>
 
  #include <linux/interrupt.h>
Line 176: Line 236:
 
  MODULE_LICENSE("GPL");
 
  MODULE_LICENSE("GPL");
  
== Uptime counter ==
+
= Uptime counter =
  
 
  #include <linux/module.h>
 
  #include <linux/module.h>
Line 201: Line 261:
 
  MODULE_LICENSE("GPL");
 
  MODULE_LICENSE("GPL");
  
== Key simulator ==
+
= Key simulator =
 
  /*  
 
  /*  
 
   *  Simulate a keypress
 
   *  Simulate a keypress
Line 257: Line 317:
 
  module_exit(print_string_exit);
 
  module_exit(print_string_exit);
  
== Memory reader ==
+
= Memory reader =
 
This reads memory address 0x100 and writes into the dmesg-syslog.
 
This reads memory address 0x100 and writes into the dmesg-syslog.
 
<pre>
 
<pre>
Line 277: Line 337:
 
</pre>
 
</pre>
  
== reboot ==
+
= 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:
 
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:
 
<pre>
 
<pre>
Line 296: Line 356:
 
</pre>
 
</pre>
  
== See also ==
+
= See also =
 
+
* [[Tutorials/How_to_program_your_own_OS]]
 +
* [[Tutorials/Assembler_Tutorial]]
 
* http://tldp.org/LDP/lkmpg/2.6/html/
 
* http://tldp.org/LDP/lkmpg/2.6/html/
 
* http://www.xml.com/ldd/chapter/book/ch06.html#t1 (jiffies)
 
* http://www.xml.com/ldd/chapter/book/ch06.html#t1 (jiffies)
 
* http://kernelnewbies.org/Drivers
 
* http://kernelnewbies.org/Drivers
 
* http://ezs.kr.hsnr.de/TreiberBuch/html/ (complete book in german)
 
* http://ezs.kr.hsnr.de/TreiberBuch/html/ (complete book in german)
 +
 +
[[Category:LowLevel]]

Latest revision as of 06:41, 23 December 2012


Contents

wait a second

This kernel module waits a second when it is initialized. You can modify it and use it e.g. to print the bytes coming from your keyboard for one second.

the source code

driver.c

#include <linux/module.h>

int init_module()
{
  printk("Starting driver...");
  unsigned long j;
  j=jiffies;
  while (jiffies-j<=HZ)
  {}
  printk("done\n");
  return 0;
}
 
void cleanup_module()
{
}
MODULE_LICENSE("GPL");

Makefile

obj-m += driver.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.ko

Get rid of it

rmmod keyb

Understanding modinfo

# modinfo driver.ko
filename:       driver.ko
license:        GPL
srcversion:     CEF3E0AB0FE04A24F00B7A6
depends:        
vermagic:       3.1.10-1.16-desktop SMP preempt mod_unload modversions 
# strings driver.ko
Starting driver...
done
license=GPL
srcversion=CEF3E0AB0FE04A24F00B7A6
depends=
vermagic=3.1.10-1.16-desktop SMP preempt mod_unload modversions 
module_layout
jiffies
printk
driver

Keyboard wire watcher

This kernel module watches, after it is loaded, for some seconds what comes from the keyboard and displays this. You will need a PS/2 keyboard, not a USB one. It works with Linux 2.6.9 kernels and higher.

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)->ops->write) (my_tty,str,strlen(str));
        ((my_tty->driver)->ops->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