Kernel programming seminar.

I have a kernel programming seminar at my job. The idea is to enrich knowledge and to ‘fortify’ what I already know.

In my experience, in order to truly learn and remember what I learned is to write it down. I will write my notes here in a hope that I don’t forget what I’ve learned. In case I do forget, I always can come here, and remind myself what I’ve learned.

So the next few posts will be my personal notepad available for everyone.

Part 1 – Introduction

One of the method to program in kernel is to use modules. In most cases these are drivers.

To compile a module, it is required to compile the module with the source code of the kernel – so called headers.

When compiling a module, use Makefile:

obj-m += acme.o
KDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

EXTRA_CFLAGS = -g

default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

The compilation result file ends with .ko. This file needs to be part of kernel. To insert or remove this file from the kernel the following commands can be used:

insmod <file name> – insert module file into the kernel
rmmod <module name> – remove module from kernel
lsmod – list modules loaded into kernel

Module has to have two functions: one activates when loading file to kernel, the other activate when removing module from kernel:
module_init(acme_init);
module_exit(acme_exit);


The function init will be called with the __init preamble :
static int __init acme_init(void)
{
}


The function exit will be called with the exit __preamble:
static void __exit acme_exit(void)
{
}

The module should have these definitions:
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Example character driver");
MODULE_AUTHOR("Free Electrons");


If license differ then GPL, dmesg log will show that the kernel is tainted:
module license 'Proprietary' taints kernel.

kernel module hello world program:

#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("Proprietary");

static int __init hello_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}

static void __exit hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_AUTHOR("Tim Goldshmit");
MODULE_DESCRIPTION("Tim's HELLO module");
MODULE_LICENSE("GPL");

C vs Python

I saw this picture on Instagram on page of some guy that teaches python

I assume that what this guy meant is that python fits best for some kind of applications than c, and for some kind of applications c fits better than python, and not that c generally sucks compared to python.

Linked List

Linked list, is a dynamic data structure in c to store data. This post is cheat sheet to myself, for every time I need to build a linked list. This is not necessary the correct way of creating the linked list, but this is my way.

Main file.

/*
 ============================================================================
 Name        : LinkedList.c
 Author      : Tim Goldshmit
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include "mylinkedlist.h"

int main(void)
{
	puts("!!!Kick this into gear!!!");
	struct my_list temp;
	memcpy(temp.mydata.full_name,"tim g",sizeof(temp.mydata.full_name));
	temp.mydata.id=1000;

	// create the root or the first node
	struct my_list root;
	memset (&root,0,sizeof(struct my_list));

	int i;
	for (i=1;i<10;i++)
	{
		temp.mydata.id=i;
		add_to_list(&root,&temp);
	}

	struct my_list *p;
	p=&root;

	remove_n_from_list(p,5);

	free_all(&root);

	return EXIT_SUCCESS;
}

the .h file

/*
 * mylinkedlist.h
 *
 *  Created on: Oct 6, 2019
 *      Author: timg
 */

#ifndef MYLINKEDLIST_H_
#define MYLINKEDLIST_H_

struct my_data
{
	char full_name[50];
	int id;
};

struct my_list
{
//	struct my_list *head;
	struct my_list *prev_node;
	struct my_list *next_node;
	struct my_data mydata;
};

int add_to_list(struct my_list *current_list,struct my_list *new_entry);
int free_all(struct my_list *any_entry);
int remove_n_from_list(struct my_list *entry_to_remove,int n);
#endif /* MYLINKEDLIST_H_ */

The .c file

/*
 * mylinkedlist.c
 *
 *  Created on: Oct 6, 2019
 *      Author: timg
 */

#include <stdio.h>
#include "mylinkedlist.h"
#include <stdlib.h>
#include <string.h>

/**
 * Add to the end if the list
 * current_list - any member of the list
 * new_entry - data to enter. the pointers do not matter, it only copies the data
 */
int add_to_list(struct my_list *current_list,struct my_list *new_entry)
{
	//In case not at the end of the node. Move to the last node
	while (!current_list->next_node==NULL)
	{
		current_list=current_list->next_node;
	}

	struct my_list *new_node=(struct my_list*)malloc(sizeof(struct my_list));
	memset (new_node,0,sizeof(struct my_list));
	current_list->next_node=new_node;
	new_node->prev_node=current_list;
	memcpy(&new_node->mydata,&new_entry->mydata,sizeof(struct my_data));
	return 0;
}

/**
 *  Remove node number n from the list.
 *  To remove current node, in the list send address of the
 * node to the function with n=0
 */
int remove_n_from_list(struct my_list *entry_to_remove,int n)
{
	int i;
	for (i=0;i<n;i++)
	{
		if (entry_to_remove==NULL)
			return -1;
		entry_to_remove=entry_to_remove->next_node;
	}

	if (entry_to_remove->prev_node==NULL && entry_to_remove->next_node!=NULL)
		entry_to_remove->next_node->prev_node=NULL;
	else if (entry_to_remove->next_node==NULL && entry_to_remove->prev_node!=NULL)
		entry_to_remove->prev_node->next_node=NULL;
	else if (entry_to_remove->next_node!=NULL && entry_to_remove->prev_node!=NULL)
	{
		entry_to_remove->prev_node->next_node=entry_to_remove->next_node;
		entry_to_remove->next_node->prev_node=entry_to_remove->prev_node;
	}

	free (entry_to_remove);
	return 0;
}

/**
 * Frees all of the memory of the linked list
 */
int free_all(struct my_list *any_entry)
{
	// get to the first node
	while (!any_entry->prev_node==NULL)
		any_entry=any_entry->prev_node;

	// free nodes one by one
	struct my_list *temp;
	while (!any_entry==NULL)
	{
		temp=any_entry->next_node;
		free(any_entry);
		any_entry=temp;
	}


	return 0;
}

This also stored in github.

https://github.com/timgold81/LinkedList

Few c tips

TL;DR:

Use % instead of ‘if’ to reset counters
Use constants
Nest struct to keep your variables in one place

Here are a few tips to programmers in c out there. I don’t say that this is the correct way to program in c. It just a few tricks that I do when programming.
Anyway, let’s say you have a function that tracking some information in an array, in length of 10.
I have the following code for this:

#include <stdio.h>
#include <string.h>
 
struct history
{
    int value;
}my_history[10];
int history_pointer=0;
 
int history_handler(int value_to_add)
{
    my_history[history_pointer].value=value_to_add;
    history_pointer++;
    if (history_pointer==10) history_pointer=0;
}
 
int main (int argc, char *argv[])
{
    int i;
    memset(&my_history,0,sizeof(my_history));
    for (i=0;i<100;i++)
        history_handler(i);
     for (i=0;i<10;i++)
        printf ("%d - %d\n",i,my_history[i]);
    return 0;    
}

For this code I”ll change a few things:

  1. I”ll remove the if in the function handler – prettier and faster code
  2. I”ll change the length of the array to constant – will allow easily to change the size of the array in the future
  3. And I”ll nest the array with a pointer – will give me one array belonging to my function, so anyone else reading my program will understand it better, and it keeps all my variable in one place. 

End result will be:

#include <stdio.h>
#include <string.h>
#define HISTORY_LENGTH 10
struct history_data
{
    int value;
};
struct history
{
    struct history_data my_data[HISTORY_LENGTH];
    int history_pointer;
}my_history;
int history_handler(int value_to_add)
{
    my_history.my_data[my_history.history_pointer].value=value_to_add;
    my_history.history_pointer=(my_history.history_pointer+1)%HISTORY_LENGTH;
}
 
int main (int argc, char *argv[])
{
    int i;
    printf("main-imp\n");
    memset(&my_history,0,sizeof(my_history));
    for (i=0;i<100;i++)
        history_handler(i);
     for (i=0;i<10;i++)
        printf ("%d - %d\n",i,my_history.my_data[i]);
    return 0;    
}

The first change I’ve added the constant instead of 10 :

#define HISTORY_LENGTH 10

I later changed every instance of 10 with the constant HISTORY_LENGTH. If in the future I will need to change the history length I will only change it here.

In the second changed, instead of using the history pointer as a global variable, I nested one struct within another. This keeps all my variable in one “place” under one struct, and any future change will be done there.

struct history_data
{
    int value;
};
 
struct history
{
    struct history_data my_data[HISTORY_LENGTH];
    int history_pointer;
}my_history;

In the third change, I removed the if:

if (history_pointer==10) history_pointer=0;

And then I changed the increment the pointer from

history_pointer++;

To

my_history.history_pointer=(my_history.history_pointer+1)%HISTORY_LENGTH;

This means increment the history pointer by 1, and use the ‘%’ remainder operand. This do the same as when this was an ‘if’ statement, but this is faster and better looking.