UNIX/Linux & C Programming:
Editing the Linux Kernel


Author: Kevin Brown


Obtaining the Kernel

Download a copy of your desired version at https://www.kernel.org/


Patching the Kernel

Compiling the kernel takes a very long time, so in order to edit it without compiling and installing it, you can patch it. Patching the kernel is done through the command patch. What patch does is take a patch file and use it to modify an existing system file. A patch file is a file generated by diff with instructions on how to convert one file to another. Because it works in this way, the patch must be the patch for the version of the kernel you are using and it can't be applied to an already patched file (unless the patch is specifically for that).

There are two main options when using patch: -p0 and -p1. These options tell patch where the kernel is. Use -p0 is the kernel source is in /usr/src/linux, otherwise use -p1 while in the directory of the kernel source.

Some patch files come compressed, to apply a compressed patch file, uncompress it and pipe the output to patch.

Here is an example of applying an uncompressed patch with the kernel source in /usr/src/linux:

$ patch -p0 < patchfile.patch 
Here is an example of applying a compressed patch with the kernel source not in /usr/src/linux:
$ zcat patchfile.gz | patch -p1
After applying the patch, the kernel does not need to be fully recompiled. You only need to run make clean, make config and make dep. See steps 1-3 of Compiling & Installing the Kernel.


Adding a System Call

When adding a system call many different files need to be edited in order for the system to recognise your call. Depending on the version of the linux kernel, some there are different files that need to be edited, and their locations may differ across versions.

Notes:

  • Some of these steps may be different on different versions of the linux kernel.
  • The version I am using is the 64 bit version of linux-source-3.13.0.
  • If using a 32 bit version, all files with the postfix _64 should be repaced with _32, on much older versions this postfix should be left out.
  • All paths given are for linux-source-3.13.0 on my system, if a file/directory is not present, use find -name <filename> to locate it.
  • If more than one file of the same name exists, edit the one that has contents matching the format of the edit (if more than one of those exist, edit the one that allows for the number you are using for your system call to match is sequence).
Creating the system call mycall:
  1. Create a directory named mycall in the source directory

  2. In this new directory put your system call
    $ cat mycall.c
    #include <linux/kernel.h>
    
    asmlinkage long mycall(int arg0){
       printk(" The System has recieved your Call: %d\n", arg0);
    
       return((long) arg0*arg0);
       }
    }
    
    the asmlinkage prefix is required to say that the arguments are taken on the stack

  3. Create a makefile named Makefile in the mycall directory containing the line:
    obj-y := mycall.o
    
  4. Edit the kernel makefile located in the source directory by changing the line containing:
    core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
    to:
    core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ mycall/
  5. Add your system call to the system call table syscalls_64.S located in <source>/arch/sh/kernel by adding a line at the end of the file
    	.long sys_mycall   /* 381 */
    keep note of what number that is down the list

  6. Define your system call in the header file unistd_64.h located in <source>/arch/sh/include/uapi/asm by adding a line before the last #endif
    #define __NR_mycall 381
    the __NR_ prefix is a macro used in linking and the number is the number found in the previous step

  7. Add the protype for your system call to the system call header file syscalls.h in <source>/include/linux by adding a prototype at the end
    asmlinkage long sys_mycall(int arg0);
  8. Finally, create a header file, mycall.h you will use to invoke your system call.
    $ cat mycall.h
    #include<linux/unistd.h>
    
    #define __NR_mycall 381
    
    _syscall1(long, mycall, int, arg0)
    
    _syscall1 is a macro defining that the system call named mycall takes 1 argument, which is an int named arg0 and returns a long
Once all of these have be completed it is time to compile and install the kernel.


Compiling & Installing the Kernel

In the linux-source directory run the following scripts in a BASH shell:

  1. make clean
  2. This will go through and remove any remnant objects that could interfere with the build
  3. make config
  4. This will configure the kernel through a series of many questions use make oldconfig to drastically reduce user input by using previous settings
  5. make dep
  6. This will go through all files and make sure all needed dependencies exist. In some versions of the kernel, step is unneeded.
  7. make bzImage
  8. This will build the kernel and compress the resulting image. *Note: This step takes quite long time, possibly hours depending on your system
After the image is created, it needs to be installed on the system, to do this the most popular tool is LILO (Linux Loader). In order to use LILO, make sure lilo is installed in /sbin. Then place the kernel image in /vmlinuz. Before running lilo, check the lilo config file in /etc/lilo.conf just to make sure it matches the data of your system. Running lilo will install the linux image and then reboot your system.


Return Home