Linuxing Celebrating Life with Linux

27Dec/092

How To Write The Linux Kernel

Kernel writing... a quiet interesting topic. People around me keep asking  how to write the kernel.Well here is answer to your question.

As i said i will tell you how to write the linux kernel, here you will see what is the kernel(ofcourse for one who don't know about the kernels and also those who are willing to write their own).

declaration: Most of the descriptions is take from different open source page, to make it a bit clear to help you out. This documentation is not at all mine, but it includes the participation of the great developers who gave us such a great operating system.

What is kernel?

The Linux kernel is the lowest level of software running on a Linux system. It is charged with managing the hardware, running user programs, and maintaining the overall security and integrity of the whole system. It is this kernel which, after its initial release by Linus Torvalds in 1991, started the development of Linux as a whole. The kernel is a relatively small part of the software on a full Linux system (many other large components come from the GNU project, the GNOME and KDE desktop projects, the X.org project, and many other sources), but it is the core which determines how well the system will work and is the piece which is truly unique to Linux.The Linux kernel is the lowest level of software running on a Linux system. It is charged withmanaging the hardware, running user programs, and maintaining the overall security and integrityof the whole system. It is this kernel which, after its initial release by Linus Torvalds in 1991, jumpstartedthe development of Linux as a whole. The kernel is a relatively small part of the softwareon a full Linux system , but it is the core whichdetermines how well the system will work and is the piece which is truly unique to Linux.

Basic programs of kernel

A kernel module has to have at least two functions: init_module which is called when the module is inserted into the kernel, and cleanup_module which is called just before it is removed. Typically, init_module either registers a handler for something with the kernel, or it replaces one of the kernel function with its own code (usually code to do something and then call the original function). The cleanup_module function is supposed to undo whatever init_module did, so the module can be unloaded safely.
Eg:hello.c

/* hello.c

*

* "Hello, world" - the kernel module version.

*/

/* The necessary header files */

/* Standard in kernel modules */

#include <linux/kernel.h>   /* We're doing kernel work */

#include <linux/module.h>   /* Specifically, a module */

/* Deal with CONFIG_MODVERSIONS */

#if CONFIG_MODVERSIONS==1

#define MODVERSIONS

#include <linux/modversions.h>

#endif

/* Initialize the module */

int init_module()

{

printk("Hello, world - this is the kernel speaking\n");

/* If we return a non zero value, it means that

* init_module failed and the kernel module

* can't be loaded */

return 0;

}

/* Cleanup - undid whatever init_module did */

void cleanup_module()

{

printk("Short is the life of a kernel module\n");

}

Multiple Kernel Versions Source Files

The system calls, which are the major interface the kernel shows to the processes, generally stay the same across versions. A new system call may be added, but usually the old ones will behave exactly like they used to. This is necessary for backward compatibility -- a new kernel version is not supposed to break regular processes. In most cases, the device files will also remain the same. On the other hand, the internal interfaces within the kernel can and do change between versions.

The Linux kernel versions are divided between the stable versions (n.<even number>.m) and the development versions (n.<odd number>.m). The development versions include all the cool new ideas, including those which will be considered a mistake, or reimplemented, in the next version. As a result, you can't trust the interface to remain the same in those versions (which is why I don't bother to support them in this book, it's too much work and it would become dated too quickly). In the stable versions, on the other hand, we can expect the interface to remain the same regardless of the bug fix version (the m number).

This version of the MPG includes support for both version 2.0.x and version 2.2.x of the Linux kernel. Since there are differences between the two, this requires conditional compilation depending on the kernel version. The way to do this to use the macro LINUX_VERSION_CODE. In version a.b.c of the kernel, the value of this macro would be 216a+28b+c. To get the value for a specific kernel version, we can use the KERNEL_VERSION macro. Since it's not defined in 2.0.35, we define it ourselves if necessary.

The /proc File System

In Linux there is an additional mechanism for the kernel and kernel modules to send information to processes -- the /proc file system. Originally designed to allow easy access to information about processes (hence the name), it is now used by every bit of the kernel which has something interesting to report, such as/proc/modules which has the list of modules and /proc/meminfo which has memory usage statistics. 

The method to use the proc file system is very similar to the one used with device drivers -- you create a structure with all the information needed for the /proc file, including pointers to any handler functions (in our case there is only one, the one called when somebody attempts to read from the /proc file). Then, init_moduleregisters the structure with the kernel and cleanup_module unregisters it.

The reason we use proc_register_dynamic is because we don't want to determine the inode number used for our file in advance, but to allow the kernel to determine it to prevent clashes. Normal file systems are located on a disk, rather than just in memory (which is where /proc is), and in that case the inode number is a pointer to a disk location where the file's index-node (inode for short) is located. The inode contains information about the file, for example the file's permissions, together with a pointer to the disk location or locations where the file's data can be found. Because we don't get called when the file is opened or closed, there's no where for us to put MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT in this module, and if the file is opened and then the module is removed, there's no way to avoid the consequences. In the next chapter we'll see a harder to implement, but more flexible, way of dealing with /proc files which will allow us to protect against this problem as well.

ex procfs.c

/* procfs.c - create a "file" in /proc

/* The necessary header files */

/* Standard in kernel modules */
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */

/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include <linux/modversions.h>
#endif

/* Necessary because we use the proc fs */
#include <linux/proc_fs.h>

 

/* In 2.2.3 /usr/include/linux/version.h includes a
* macro for this, but 2.0.35 doesn't - so I add it
* here if necessary. */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
#endif

 

/* Put data into the proc fs file.

Arguments
=========
1. The buffer where the data is to be inserted, if
you decide to use it.
2. A pointer to a pointer to characters. This is
useful if you don't want to use the buffer
allocated by the kernel.
3. The current position in the file.
4. The size of the buffer in the first argument.
5. Zero (for future use?).

Usage and Return Value
======================
If you use your own buffer, like I do, put its
location in the second argument and return the
number of bytes used in the buffer.

A return value of zero means you have no further
information at this time (end of file). A negative
return value is an error condition.

For More Information
====================
The way I discovered what to do with this function
wasn't by reading documentation, but by reading the
code which used it. I just looked to see what uses
the get_info field of proc_dir_entry struct (I used a
combination of find and grep, if you're interested),
and I saw that it is used in <kernel source
directory>/fs/proc/array.c.

If something is unknown about the kernel, this is
usually the way to go. In Linux we have the great
advantage of having the kernel source code for
free - use it.
*/
int procfile_read(char *buffer,
char **buffer_location,
off_t offset,
int buffer_length,
int zero)
{
int len; /* The number of bytes actually used */

/* This is static so it will still be in memory
* when we leave this function */
static char my_buffer[80];

static int count = 1;

/* We give all of our information in one go, so if the
* user asks us if we have more information the
* answer should always be no.
*
* This is important because the standard read
* function from the library would continue to issue
* the read system call until the kernel replies
* that it has no more information, or until its
* buffer is filled.
*/
if (offset > 0)
return 0;

/* Fill the buffer and get its length */
len = sprintf(my_buffer,
"For the %d%s time, go away!\n", count,
(count % 100 > 10 && count % 100 < 14) ? "th" :
(count % 10 == 1) ? "st" :
(count % 10 == 2) ? "nd" :
(count % 10 == 3) ? "rd" : "th" );
count++;

/* Tell the function which called us where the
* buffer is */
*buffer_location = my_buffer;

/* Return the length */
return len;
}

struct proc_dir_entry Our_Proc_File =
{
0, /* Inode number - ignore, it will be filled by
* proc_register[_dynamic] */
4, /* Length of the file name */
"test", /* The file name */
S_IFREG | S_IRUGO, /* File mode - this is a regular
* file which can be read by its
* owner, its group, and everybody
* else */
1, /* Number of links (directories where the
* file is referenced) */
0, 0, /* The uid and gid for the file - we give it
* to root */
80, /* The size of the file reported by ls. */
NULL, /* functions which can be done on the inode
* (linking, removing, etc.) - we don't
* support any. */
procfile_read, /* The read function for this file,
* the function called when somebody
* tries to read something from it. */
NULL /* We could have here a function to fill the
* file's inode, to enable us to play with
* permissions, ownership, etc. */
};

 

 

/* Initialize the module - register the proc file */
int init_module()
{
/* Success if proc_register[_dynamic] is a success,
* failure otherwise. */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0)
/* In version 2.2, proc_register assign a dynamic
* inode number automatically if it is zero in the
* structure , so there's no more need for
* proc_register_dynamic
*/
return proc_register(&proc_root, &Our_Proc_File);
#else
return proc_register_dynamic(&proc_root, &Our_Proc_File);
#endif

/* proc_root is the root directory for the proc
* fs (/proc). This is where we want our file to be
* located.
*/
}

/* Cleanup - unregister our file from /proc */
void cleanup_module()
{
proc_unregister(&proc_root, Our_Proc_File.low_ino);
}

this is a part of kernel writing will get the rest soon till then enjoy
Regards,
neal

Share and Enjoy:
  • Print
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • StumbleUpon
  • Twitter
Comments (2) Trackbacks (0)
  1. Hi Neal,
    Good post, however several points come to my mind
    a) This is an introduction on how to write a Kernel module and not on how to write the linux kernel itself. You need to change the topic and the relevant text.
    b) You have not talked about how to actually compile the kernel module, I am assuming that you were going to talk in the later posts on how to compile the module itself ?
    c) The paragraph which stated that “The Linux kernel versions are divided between the stable versions (n..m) and the development versions (n..m).” is no longer applicable. Check the links http://kerneltrap.org/Linux/Kernel_Release_Numbering_Redux and
    http://en.wikipedia.org/wiki/Software_versioning#Odd-numbered_versions_for_development_releases
    d) I have always found the book “Linux Device Drivers” available for download at http://lwn.net/Kernel/LDD3/ to be a very useful resource.

  2. well here i want to tell you two things….
    1. the stable and unstable version thing is still in the market
    2. All about the level of post this post is made with the purpose to give knowledge to newbies and all who are in this field.

    I will add the entries on how to write the kernel soon enough so need not to worry about that.

    wait for my next post.

    c ya


Leave a comment


No trackbacks yet.

Get Adobe Flash playerPlugin by wpburn.com wordpress themes