Showing posts with label Linux Kernel. Show all posts
Showing posts with label Linux Kernel. Show all posts

Linux Kernel Modules

Linux kernel modules are pieces of code that can be loaded and unloaded from kernel on demand.

Kernel modules offers an easy way to extend the functionality of the base kernel without having to rebuild or recompile the kernel again. Most of the drivers are implemented as a Linux kernel modules. When those drivers are not needed, we can unload only that specific driver, which will reduce the kernel image size.

Kernel modules will have extension .ko
Kernel modules will operate on kernel space.
All Drivers are modules. Not all modules are drivers.

Kernel Modules Commands:
lsmod: To see list of modules that already loaded on system
insmod: To insert modules into kernel
modinfo: To display modules information
rmmod: To remove modules from kernel

How to Write Kernel Modules:

module.c
#include <linux/module.h>    // included for all kernel modules
#include <linux/kernel.h>    // included for KERN_INFO
#include <linux/init.h>      // included for __init and __exit macros

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Name");
MODULE_DESCRIPTION("Hello World module");

static int __init hello_init(void)
{
    printk(KERN_INFO "Hello world!\n");
    return 0;    // Non-zero return means that the module couldn't be loaded.
}

static void __exit hello_cleanup(void)
{
    printk(KERN_INFO "Cleaning up module.\n");
}

module_init(hello_init);
module_exit(hello_cleanup);
Makefile to compile module:
obj-m += hello.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
When a module is inserted into the kernel, the module_init macro will be invoked, which will call the function hello_init. Similarly, when the module is removed with rmmod, module_exit macro will be invoked, which will call the hello_exit. Using dmesg command, we can see the output from the sample Kernel module.

printk() is used for printing kernel messages

Latest Kernel version

Current stable kernel version: 4.5.1
https://www.kernel.org/

Linux: Message Queues

Message Queue is a linked list of message structures stored inside the kernel’s memory space and accessible by multiple processes. 

New messages are added at the end of the queue. 


Messages may be obtained from the queue either in a FIFO manner (default) or by requesting a specific type of message (based on message type).

Each message has a message type associated with it. A Message Queue reader can specify which type of message that it will read. Or it can say that it will read all messages in order.

It is quite possible to have any number of Msg Queue readers, or writers. In fact the same process can be both a writer and a reader.


  • Each message structure must start with a long message type:
      struct mymsg 
      {
           long msg_type;
           char mytext[512]; /* rest of message */
           int somethingelse;
      };

Each message queue is limited in terms of both the maximum number of messages it can contain and the maximum number of bytes it may contain.
 

New messages cannot be added if either limit is hit (new writes will normally block).

On linux, these limits are defined as (in /usr/include/linux/msg.h):
        –MSGMAX 8192 /*total number of messages */
        –MSBMNB 16384 /* max bytes in a queue */

Creating a Message Queue:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

            int msgget (key_t key, int msgflg);


The key parameter is either a non-zero identifier for the queue to be created or the value IPC_PRIVATE, which guarantees that a new queue is created. 

The msgflg parameter is the read-write permissions for the queue OR’d with one of two flags: 

IPC_CREAT will create a new queue or return an existing one.

IPC_EXCL added will force the creation of a new queue, or return an error.

Writing to a Message Queue:

           int msgsnd (int msqid, const void * msg_ptr, size_t msg_size, int msgflags);

   msgqid is the id returned from the msgget call
   msg_ptr is a pointer to the message structure 
   msg_size is the size of that structure 
   msgflags defines what happens when no message of the appropriate type is waiting, and can be set to the following: 
          IPC_NOWAIT (non-blocking, return –1 immediately if queue is empty)

Reading from a Message Queue:

      int msgrcv(int msqid, const void * msg_ptr, size_t msg_size, long msgtype, int msgflags);

   msgqid is the id returned from the msgget call
   msg_ptr is a pointer to the message structure
   msg_size is the size of that structure
   msgtype is set to: = 0 first message available in FIFO stack
                             > 0 first message on queue whose type equals type 
   msgflags defines what happens when no message of the appropriate type is waiting, and can be set to the following: 

        IPC_NOWAIT (non-blocking, return –1 immediately if queue is empty)

Message Queue Control:

    int msgctl(int msqid, int cmd, struct msqid_ds * buf);

Linux: Pipes(Half Duplex)

Pipe is an effective way of communication(Half Duplex) between process. Pipe has two descriptors. One descriptor is used for reading while other end is used for writing.

Usage of pipe is to have communication between child and parent process. We also use pipe to redirect of output of a process to another process. We often use pipe in our shell scripts.


With half-duplex pipes, any connected processes must share a related ancestry. Since the pipe resides within the confines of the kernel, any process that is not in the ancestry for the creator of the pipe has no way of addressing it. This is not the case with named pipes (FIFOS).

SYSTEM CALL: pipe(); 
PROTOTYPE: int pipe( int fd[2] ); 

RETURNS: 0 on success -1 on error: 
               errno = EMFILE (no free descriptors) 
                          EMFILE (system file table is full) 
                          EFAULT (fd array is not valid) 

NOTES: fd[0] is set up for reading, fd[1] is set up for writing

Linux: Kernel Space and User Space

Linux kernel runs under a special privileged mode as compared to user space applications. 

Kernel runs in a protected memory space and it has access to entire hardware. This memory space and this privileged state collectively known as kernel space or kernel mode.

User space programs runs in a unprivileged mode and it has limited access to resources and hardware.

User space applications can not directly access to kernel memory but kernel has access to entire memory space.

What is Spinlock?

A spinlock is a lock where the thread simply waits in a loop ("spins") repeatedly checking until the lock becomes available. Since the thread remains active but isn't performing a useful task, the use of such a lock is a kind of busy waiting.

Spinlocks are efficient if threads are only likely to be blocked for a short period of time, as they avoid overhead from operating system process re-scheduling or context switching. For this reason, spinlocks are often used inside operating system kernels. However, spinlocks become wasteful if held for longer durations, preventing other threads from running and requiring re-scheduling.

Linux Kernel

A Kernel is a central component of an operating system.It acts as an interface between the user applications and the hardware.The sole aim of the kernel is to manage the communication between the software (User Level applications) and the hardware(CPU,disk memory etc).

Latest Stable Kernel version is: 3.8.2 (https://www.kernel.org/)

The main tasks of the kernel are:
  • Process management
  • Device management
  • Memory management
  • Interrupt Handling
  • I/O communication
  • File Systems