Observe that init_module() is invoked when a module is first loaded using the `insmod` (or `modprobe`) command. Likewise, cleanup_module() is called when a module is removed from the kernel using `rmmod modulename`.
HINT: A helpful reference for this work is "Linux Device Drivers", by A. Rubini O'Reilly, ISBN: 1-56592-292-1, 1998, or the recently released second edition.
To avoid having to specify the appropriate compiler options, the following preprocessor directives should be placed somewhere near the beginning of your module source file:
#ifndef MODULE
#define MODULE
#endif
#ifndef __KERNEL__
#define __KERNEL__
#endif
The following template Makefile will help with the compilation of your source file module_name.c into an object module_name.o :
INC_PATH =
/usr/src/linux/include
SRCS
=
CFLAGS = -O -Wall
-I$(INC_PATH)
CC
= gcc
all: test_syscall_module.o test_syscall
.c.o:
$(CC) $(CFLAGS) -c $*.c
clean:
rm *~ *.o
You can use any symbols (i.e., functions, global variables etc) that are exported via kernel/ksyms.c in your module. Try `cat /proc/ksyms | more` to see the available symbols. Additionally, you can use the printk() kernel function to print your messages to the console. If they do not appear on the console, this may be due to an insufficiently high enough priority for the message to appear on the console (or logging of kernel messages has been disabled entirely). You may need to edit /etc/syslog.conf and insert a line such as:
kern.* /dev/console
to enable console logging of kernel messages. Note that when you reboot your (virtual) machine after editing this file, you may see many additional text messages, which should not be cause for alarm.
If you do not modify /etc/syslog.conf, you can always look at the messages in /var/log/messages or simply issue the command `dmesg`. Alternatively, you might want to insert the following code in your module and invoke it instead of using printk():
/* 'printk' version that prints to active tty. */
void my_printk(char *string)
{
struct tty_struct *my_tty;
my_tty = current->tty;
if (my_tty != NULL) {
(*(my_tty->driver).write)(my_tty, 0, string,
strlen(string));
(*(my_tty->driver).write)(my_tty, 0, "\015\012",
2);
}
}
int kprint (char *msg);You will need* to add a new system call entry in arch/i386/kernel/entry.S and include/asm-i386/unistd.h. If you create a new "stub" entry for your system call in kernel/sys.c you will be able to build your modified kernel without any unresolved symbol errors. The true system call (defined as sys_kprint()) will actually go in the body of your module and will override the stub routine when the module is loaded.
You will then need to rebuild your new kernel image, modifying
/etc/lilo.conf or /etc/grub.conf as necessary (NOTE: if using lilo as
your primary boot loader, you will need to rerun `lilo` before changes
to /etc/lilo.conf take place).
A good source of information on this subject can be found in the Linux
Document Project. This is a great source of information on many aspects
of Linux but of particular interest for this assignment is the HOWTO
document
on building
and
configuring a new kernel.
The next step is to write a simple program that makes use of your system call. Observe that there is no reference to this system call from within the C library (libc), so you'll have to explicitly declare its prototype in the correct format, using one of the syscall macros. Specifically, this will be the _syscall1() macro defined in linux/unistd.h, since your system call takes one argument.
*Footnote: technically speaking, you can actually implement a system
call without modifying the core kernel. I'll leave this for you to
investigate, if you so wish. In any case, you should practice builing
the Linux kernel if you haven't done this before.