Tuesday, September 30, 2008

Char Drivers: Preliminaries

This is what I could gather from Linux Device Drivers Version 3. I have consulted a few other books but this one is lightyear ahead of others and should be the one point reference.

Important Data structures :-
1. file structure :
[*] Defined by linux/fs.h
[*] represents an open file [ every open file in linux has an associated struct file in kernel space]
[*] created by kernel on "open" and is passed to any driver method/operation that operated on the file. When all the instances of the file are closed, the kernel releases the data structure.

This is what the structure looks like

struct file
{
struct list_head f_list;
struct dentry *f_dentry;
struct file_operations *f_op;
atomic_t f_count;
unsigned int f_flags;
mode_t f_mode;
loff_t f_pos;
unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
struct fown_struct f_owner;
unsigned int f_uid, f_gid;
int f_error;
unsigned long f_version ;
void *private_data;
};

Of these f_op is the most important data structure and our next target.

2. File Operations
[*] Collection of function pointers which point to a function in the driver. These functions implement a specific operation e.g read , write , open , close etc. [ If you dont know what function pointers are or how to use them, you have no business reading any further.]
[*] For unsupported operations NULL should be used.
Interesting point
suppose we have
struct file *filp;
then filp ->f_op is not saved by the kernel. This means that the file operations associated by a file can be changed.These new methods will be effective after the return to the caller.
Example:
struct file_operations nemesis_fops = {
.owner = THIS_MODULE,
.llseek = nemesis_llseek,
.read = nemesis_read,
.write = nemesis_write,
.ioctl = nemesis_ioctl,
.open = nemesis_open,
.release = nemesis_release,
};

3. Inode structure
[*] It is used by the kernel to represent files.
[*] file structure only represents an open file. Therefore for a single file , there can be numerous file structure representing miltiple open descriptors but they all point to a single inode structure

Sunday, September 28, 2008

First Steps with Linux Kernel Programming

Like any programming endeavour, this one begins by saying hello to the world and remembering MAHAKALI : The supreme consciousness and the creatrix of the universe.

So without much ado, here are the steps :-

1. create a file called hello.c.Use an editor of your choice. Some people like vi/emacs whereas others use kate or gedit. Suit yourselves guys.

2. your first kernel program looks like this :-

#include <> /* for __init and __exit */
#include <> /* for MODULE related macros */
#include <>

/* this is the function which is invoked on issuing the "insmod" command */
/* unlike userland programs, there is no main function. Init module is the entry point */

static int __init hello_init(void)
{
printk(KERN_ALERT "Jai Mahakali: Jai Bhawani: Welcome !\n");
return 0;
}

/* ths is the function which is invoked on issuing the "rmmod" command */
/* it is an indication to the kernel that this module is no longer needed and can be unloaded */
static void __exit hello_exit(void)
{
printk(KERN_ALERT "Jai Kaal Bhairav : Adieus \n");
}

/* module_init : adds a special section to module's object code indicating the module initialization func */
/* module exit : ditto */

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("Dual BSD\GPL"); /* add this if you dont want to get kernel taint warnings */
MODULE_AUTHOR("Nemesis KERNELEXPLOIT@GMAIL.COM");
MODULE_DESCRIPTION("Hello World");

3. Write the make file (courtesy Linux Device Drivers 3rd Edition). I don't exactly enjoy writing makefiles. Infact I am yet to meet a person who does.

-------------------------------------------x-------------------------------------------------x------------------------------------x------------------------

# To build modules outside of the kernel tree, we run "make"
# in the kernel source tree; the Makefile these then includes this
# Makefile once again.
# This conditional selects whether we are being included from the
# kernel Makefile or not.
ifeq ($(KERNELRELEASE),)

# Assume the source tree is where the running kernel was built
# You should set KERNELDIR in the environment if it's elsewhere
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
# The current directory is passed to sub-makes as argument
PWD := $(shell pwd)

modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

.PHONY: modules modules_install clean

else
# called from kernel build system: just declare what our modules are
obj-m := hello.o

endif

-------------------------------------------x-------------------------------------------------x------------------------------------x-----------------------

4. issue the following command

nemesis@tantra:~/device-drivers$ make
make -C /lib/modules/2.6.18-6-686/build M=/home/nemesis/device-drivers modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.18-6-686'
CC [M] /home/nemesis/device-drivers/hello.o
/home/nemesis/device-drivers/hello.c:19:1: warning: unknown escape sequence '\G'
/home/nemesis/device-drivers/hello.c:21:35: warning: no newline at end of file
Building modules, stage 2.
MODPOST
CC /home/nemesis/device-drivers/hello.mod.o
LD [M] /home/nemesis/device-drivers/hello.ko
make[1]: Leaving directory `/usr/src/linux-headers-2.6.18-6-686'
nemesis@tantra:~/device-drivers$

5. Wonderful!!! we have our shiny new module ready!!! Execute the insmod command. Well you need to be root to be able to insert a module into the kernel. If you are not a part of the sudoer's group you will not be able to proceed further. But we are not going to be daunted by a little glitch are we now ?

here is what to do:
sudo /usr/sbin/visudo
add the following line at the end of this file
your-username ALL=(ALL) ALL

Now that we have this out of our way , proceed with insmod

nemesis@tantra:~/device-drivers$sudo /sbin/insmod hello.ko
nemesis@tantra:~/device-drivers$dmesg

here is what you see at the end of the output
Jai Mahakali: Jai Bhawani: Welcome !

Now its time we unload the module
nemesis@tantra:~/device-drivers$sudo /sbin/rmmod hello.ko
nemesis@tantra:~/device-drivers$dmesg

here is what you see at the end of the output
Jai Kaal Bhairav : Adieus


6 . Its time we gather some info about our module
nemesis@tantra:~/device-drivers$sudo /sbin/modinfo hello.ko
filename: hello.ko
license: Dual BSDGPL
author: Nemesis KERNELEXPLOIT@GMAIL.COM
description: Hello World
vermagic: 2.6.18-6-686 SMP mod_unload 686 REGPARM gcc-4.1
depends:

Some Kernel Modules may accept user-specified parameters.


modinfo -p ${modulename}

The command above shows a current list of all parameters of a loadable
module. Loadable modules, after being loaded into the running kernel, also
reveal their parameters in /sys/module/${modulename}/parameters/. Some of these parameters may be changed at runtime by the command

echo -n ${value} > /sys/module/${modulename}/parameters/${parm}

7. at a final look at the elf-object code of hello.ko to see the __init section. Just to let you guys know that I wasnt bluffing !

nemesis@tantra:~/device-drivers$readelf -a hello.ko
Symbol table '.symtab' contains 32 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 SECTION LOCAL DEFAULT 1
2: 00000000 0 SECTION LOCAL DEFAULT 2
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 0 SECTION LOCAL DEFAULT 5
6: 00000000 0 SECTION LOCAL DEFAULT 6
7: 00000000 0 SECTION LOCAL DEFAULT 7
8: 00000000 0 SECTION LOCAL DEFAULT 8
9: 00000000 0 SECTION LOCAL DEFAULT 9
10: 00000000 0 SECTION LOCAL DEFAULT 10
11: 00000000 0 SECTION LOCAL DEFAULT 11
12: 00000000 0 SECTION LOCAL DEFAULT 12
13: 00000000 0 SECTION LOCAL DEFAULT 13
14: 00000000 0 SECTION LOCAL DEFAULT 14
15: 00000000 0 SECTION LOCAL DEFAULT 15
16: 00000000 0 SECTION LOCAL DEFAULT 16
17: 00000000 0 SECTION LOCAL DEFAULT 17
18: 00000000 0 FILE LOCAL DEFAULT ABS hello.c
19: 00000000 12 FUNC LOCAL DEFAULT 2 hello_exit
20: 00000000 14 FUNC LOCAL DEFAULT 4 hello_init
21: 00000000 20 OBJECT LOCAL DEFAULT 7 __mod_license19
22: 00000020 36 OBJECT LOCAL DEFAULT 7 __mod_author20
23: 00000044 24 OBJECT LOCAL DEFAULT 7 __mod_description21
24: 00000000 0 FILE LOCAL DEFAULT ABS hello.mod.c
25: 00000060 57 OBJECT LOCAL DEFAULT 7 __mod_vermagic5
26: 00000000 128 OBJECT LOCAL DEFAULT 8 ____versions
27: 00000099 9 OBJECT LOCAL DEFAULT 7 __module_depends
28: 00000000 608 OBJECT GLOBAL DEFAULT 10 __this_module
29: 00000000 12 FUNC GLOBAL DEFAULT 2 cleanup_module
30: 00000000 14 FUNC GLOBAL DEFAULT 4 init_module
31: 00000000 0 NOTYPE GLOBAL DEFAULT UND printk

Well Adieus for now! Next up is a dummy char driver.

Saturday, September 27, 2008

Linux Device Drivers: Device Types

Classes of Linux Devices

1. Character [CHAR] Devices
- Can be accessed as a stream of bytes 
- Normally MUST implement open, close, read and write functionalities
- Can be accessed ONLY Sequentially unlike a regular file where it is posssible to move back & forth. However there can be a workaround for this using mmap() and lseek operations
- Mapped to a node in the filesystem e.g. /dev/ttyS0
- examples : serial ports, text consoles

2. Block Devices
- normally capable of hosting a filesystem
- Mapped to a node in the filesystem 
- In most of UNIX systems, block devices can ONLY handle I/O operations that transfer one or more blocks.
- Linux allows block devices to be read and written to like char devices

3. Network Interfaces
- Normally a hardware interface but software interface can also exist e.g. the loopback
- Unlike char device it is NOT stream oriented
- not mapped to a node in filesystem
- instead of read and write , they support receieve and transmit operations

Sunday, September 21, 2008

Interview FAQs : ARM Processors

1. Starting with a sitter : What are ARM and Thumb Modes of operation of an ARM processor ?

2. What are the tradeoffs in their respective usage ? Which mode does it Start in?

3.  Why are the FIQs faster ? 

4. What are the pipelining stages in ARM7 and ARM9 ? 

Saturday, September 20, 2008

Interview FAQs: C programming

1.  What is the significance of the Keyword "static" in C ?  [Believe me 99% of programmers either give a completely wrong answer or an incomplete one ]

[Answer] Well the answer I would look forward to is :-
a .  static limits the scope of a variable or a function to a file : NO EXTERNAL LINKAGE 
b.  function :  Implication of point (a) is that a function declared static cannot be invoked from anyother file than in which the function is defined.
c.  variable : 
global static: it is same as a global  variable with just the restriction of scope steming rom point (a) i.e. scope is limited to the file

Static variables are initialized only once.
 
local static :  the value persists across function calls and scope is limited to a block
          
                      

2. Inline Vs Macros

3.  What does the qualifier Volatile signify ? Where would you use them. Give examples.

4.  How about "const" ? 

5.  Can a variable be const and volatile at the same time ? Substatiate your argument. [ONLY If the person being interviewed answers question 3 and 4 correctly ]

6.  What is endian-ness ? Write a small piece of code to output the endian-ness of the architecture

7. What are register variables ? Why cannot we take the address of the register variable ?

8. Are pointers and arrays the same? [one of my favourites]
[Answer] : N0: Pointers and arrays are NOT the same although many programmers believe that they are. K&R are explicitly says that " pointers and arrays are equivalent as formal arguments to a function". That is it.

To clinch the argument (pun intended) consider this :-

int *pointer;
int array[10];

pointer++  /*  Allowed */
array++   /*  Not Allowed  */

Modifying the base address of an array is not permitted. No such restrictions apply to a pointer.

But as formal parameters f0r a function definition, following are equivalent:-

char *s;
and char s[ ];

9.  Why is the lifetime of a local variable only till the duration of the local block whereas static variable retain their values across function calls ?

[Answer] local variables (automatic) are placed on stack, the contents of which depend on the function execution. When a function is being executed , its arguments as well as all the local variables are stored on the stack. As soon as the function exits , this place is freed automatically to make way for the arguments and local variables of the next function.Therefore, an automatical variable loses its value as soon as the function exits.

whereas, a static variable is stored onto the data segment. This segment persists throughout the execution of the program and hence variables stored on the data segment retain their values across function calls.

10. function pointers. Invocation and use.
[Answer] : 
a. Function pointers are variables which point to the address of a function.
b. Function pointers are less error prone than normal pointers as memory is never allocated or deallocated with them
c. protype :  

int (*pFunc)(); /* pFunc is a pointer to a func that returns an int and doesnt take a param */

No actual data is being pointed to yet.

Now,let us assume that there is a function with the following prototype:-
int func( ) ;

In this case the following two operations are equivalent :- 

pFunc = func;
pFunc = & func;

Usage :
 a . To replace the switch/if statements. Most commonly used in implementing state machines
 b.  Implementing call backs