Sunday, 6 July 2014

[Kernel Programming] Cross compile a module for ARM platform

My initial Kernel Programming posts in this blog contains the following info

  • how to write a module,
  • how to compile a module using a Makefile,
  • how to insert/remove a module into linux platform machine
Please check my previous posts for this information below

Now, I will share the required data for writing a simple module for ARM platform in this post. Please follow below steps for the same. 

[Note: You should have working linux kernel source code, and able to flash this code on any android device for testing this module.]

Step-1: Goto Linux Kernel source directory and set $TOP variable with this path
Example: If kernel source code is present on home directory then
export TOP = $(/home/your-machine-username/kernel_source_dir)

Step-2: Goto kernel folder from $TOP and create a temporary directory there.
Example: 1. cd $TOP/kernel
                2. mkdir test

Step-3: Now, add simple module file in the test directory.
Example: simple.c

#include<linux/module.h> /* Needed by all modules *MUST* */

int init_module(void) {
         printk(KERN_ALERT "1st module program: Module Inserted\n");
         return 0;
 }

 void cleanup_module() {
         printk(KERN_ALERT "1st module program: Module Removed\n");
 }

Step-4: Add Makefile for this module.
Example: Makefile
obj-m += simple.o

Only above one line is enough here.

Step-5: Now, we have two files in the test directory. They are simple.c and Makefile. Goto kernel folder (cd $TOP/kernel)
Step-6: Compile our test module using make command

make -j4 ARCH=arm CROSS_COMPILE=$TOP/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin/arm-linux-androideabi- O=$TOP/out/target/product/<product-name>/obj/KERNEL M=$TOP/kernel/test

Options description:

-j4: Describes how many threads GNU compiler will make use of, to compile the module. Normally, the number(just after 'j') should be twice the number of CPU cores available for your pc.

ARCH: Describes the destination platform architecture. The name of the architecture can be found in the $TOP/kernel/arch/ directory.
Example: arm platform: $TOP/kernel/arch/arm
                arm64 platform: $TOP/kernel/arch/arm64

CROSS_COMPILE: Specifies the correct tools path to be used for generating object files and binary files for our test module.

O: Specifies the path to where the generated object files have to go.

M: Path to input module directory to compile the required module.

Step-7: After successful compilation of our test module, we can see simple.ko file get generated in $TOP/kernel/test directory.

Step-8: Now, insert this module into destination platform using insmod command.
If the destination platform is accessed through adb shell then do the following.
  1. sudo adb push $TOP/kernel/test/simple.ko /data
  2. sudo adb shell
  3. su -
  4. cd /data
  5. Insert our test module (simple.ko) using below command
    insmod simple.ko
  6. We can see the output of the insmod using below command
    dmesg
    And observe, "1st module program: Module Inserted" got printed in the log
  7. Use below command for removing our module
    rmmod simple
I hope this data is useful to compile any module for different platform.

References:
https://www.kernel.org/doc/Documentation/kbuild/kbuild.txt


Tuesday, 8 April 2014

[Kernel Programming] Allocation of memory in Kernel

Allocation of memory in Kernel


kmalloc()kzalloc()kcalloc()vmalloc()
Allocates contiguous physical blocks of memory in byte-sized chunksAllocates contiguous physical blocks of memoryAllocates memory for an arraysame as kmalloc, except it allocates memory that is only virtually contiguous
Memory is not set to zeroMemory is set to zeroMemory is set to zerounderling physical memory can be discontiguous
void * kmalloc (size_t size, int flags)void * kzalloc (size_t size, int flags)void * kcalloc  (size_t n, size_t size, unsigned int __nocast flags);void * vmalloc (unsigned long size)
Depends on the flag used, it may sleepDepends on the flag used, it may sleepDepends on the flag used, it may sleepCan sleep, so don’t use it in interrupt context
Can allocate upto 4MBytesSame as kmallocNeed to check ?Can obtain very large regions of memory
Simple and fastSimple, preferable and fastSimple and fastSlow compare to kmalloc


Vmalloc(): Slower and not advisable if memory requirement is less. Because,
  1. Makes non-contiguous physical memory to continuous virtual memory
  2. Setting up the page table entries
  3. Pages obtained from vmalloc() must be mapped to their individual pages since physical memory is not contiguous
  4. Results in much greater TLB, performance is affected.

Note: malloc() function also works in same manner. i.e. allocated memory in continuous in virtual address space of the processor, but there is no guarantee that they are contiguous in the physical address space (physical RAM)

Flag: controls the behavior of memory allocation and divided into 3 groups
–Action modifiers: How to allocate memory. Ex: can sleep or not
–Zone modifiers: Where the request should be satisfied. (ex: DMA buffers)
–Types: types of allocation


FLAG TypeAction ModifierZone Modifier
GFP_KERNEL(__GFP_WAIT | __GFP_IO | __GFP_FS) -NA-
GFP_ATOMIC__GFP_HIGH -NA-
GFP_DMA__GFP_DMA


GFP_ATOMIC:  Allocation is High priority and does not sleep. This flag will  be used in Interrupt handlers, bottom halves where kernel should not sleep
GFP_KERNEL: Allocation will be Normal priority and can be used in process context, and safe to sleep

Action Modifiers and Zone Modifiers:

__GFP_HIGH: The kernel can access emergency pools.
__GFP_WAIT: The kernel can sleep
__GFP_IO: The kernel can start disk I/O
__GFP_FS: The kernel can start filesystem I/O
__GFP_DMA: Allocate only DMA-capable memory

References:
Third Edition of Linux Device Drivers, by Jonathan Corbet

Monday, 16 December 2013

[C Programming] Function Pointers basics in C

Function Pointers

Definition

Function pointers are pointers, which points to the address of a function. Function pointers are variables only, so it will be declared and defined like other variable.

Syntax

<data_type> (*function_pointer_name) (variable data_type list) = NULL; /* defining function pointer and initializes to NULL */

The signature of this function pointer should match with the signature of function which address is stored in this pointer.

Sample code

float doMath (float a, float b) {
 /*
    desired code
 */
return result;
}

int main() {
float (*math_pointer) (float, float) = NULL;

math_pointer = &doMath; /* pointer to function doMath() */

output = math_pointer (10.5, 11.1);
/*
   desired code
*/
return 0;
}


Usage

  1. To replace switch/if conditional statements
  2. To implement late-binding (runtime binding) (C++ scenario)
  3. To implement callbacks

Example for Usage-1

#include<stdio.h>

float addition (float a, float b) {
 return a + b;
}

float subtraction (float a, float b) {
 return a - b;
}

float multiplication (float a, float b) {
 return a * b;
}

void select (float a, float b, char opCode) {
float result;
switch(opCode)
{
 case '+': result = addition(a, b); break;
 case '-': result = subtraction(a, b); break;
 case '*': result = multiplication (a, b); break;
}
printf("Result: %f\n", result);
}

/* Replace the above switch statement with function pointer */
void select_function_pointer (float a, float b, float (*math_pointer)(float, float)) {
float result = math_pointer(a, b); /* Calling function using function pointer */
printf("Result: %f\n", result);
}

void main()
{
  float a, b;
   
  select(10, 15, '+');
  select_function_pointer (10, 15, &addition); /* Passing function as an address argument */
}


Array of Function Pointers

Since the Function pointer is a variable, we can define array of function pointer using below syntax.


Syntax-I
tyepdef <data_type> function_pointer_name (argument data_type list);
function_pointer_name array_fun_pointer [10] = {NULL};

Syntax-II
<data_type> (*array_fun_pointer[10])(argument data_type list) = {NULL};

array_fun_pointer [0] = &function1;
.
.
Calling function using function pointer
(*array_fun_pointer[0]) (arguments); or
array_fun_pointer[0](arguments);


Implementation of Callbacks using Function Pointers

It is a bit more complex syntax. Try to understand the callback mechanism in C by using below sample code:

void insert_array (int *array, size_t size, int (*getNextValue) (void))
{
     for (int i = 0; i < size; i++)
        array[i] = getNextValue();
}

int getNextRandomValue()
{
   return rand();
}

int main()
{
   int a[10];
   insert_array(a, 10, &getNextRandomValue);
}

Here, the function insert_array() takes the 3rd argument as the function address using function pointer getNextValue. And, the callback function is getNextRandomValue(), returns random value. The function insert_array() calls this callback function using function pointer getNextValue for inserting the values into the array.

The similar explanation can be found here (from Stackoverflow)

Monday, 2 December 2013

Tasklet Vs Work queues [Part-II]

For Tasklet Vs Work queues [Part-I], please click here.

Work queues

Work queues are added in linux kernel 2.6 version. And, one major difference between Work queues and Tasklets is that the handler function of work queues can sleep but not possible in the case of Tasklet's handler function.

Another difference is that the Work queues have higher latency than Tasklet.

We should look at two main data structures in the Work queue mechanism.
  1. struct workqueue_struct
  2. struct work_struct
The core work queue is represented by structure struct workqueue_struct, which is the structure onto which work is placed. This work is added to queue in the top half (Interrupt context) and execution of this work happened in the bottom half (Kernel context).

The work is represented by structure struct work_struct, which identifies the work and the deferral function.

Kernel threads named "events/X" will extract work from the core work queue and activates the work's handler function.

Work queue APIs

Create and destroy work queue structure

struct workqueue_struct *create_workqueue(name); /* Creates core workqueue */
void destroy_workqueue(struct workqueue_struct *); /* Destroy the workqueue */

Initialization of work structure

Work queue API provides 3 macros which initializes the work and also set the function handler.

INIT_WORK(work, function);
INIT_DELAYED_WORK(work, function); /* if we add any delay before adding this work into work queue structure */
INIT_DELAYED_WORK_DEFERRABLE(work, function);

EnQueue work on to work queue

Below are work queue APIs used for adding queue on to work queue.

int queue_work (struct workqueue_struct *wq, struct work_struct *work);
int queue_work_on (int cpu, struct workqueue_struct *wq, struct work_struct *work); /*  specify the CPU on which the handler should run */
int queue_delayed_work (struct workqueue_struct *wq, struct delayed_work *work), unsigned long delay); /* Queue specified work on to specified work queue after delay */
int queue_delayed_work_on (int cpu, struct workqueue_struct *wq, struct delayed_work *work), unsigned long delay);

The below functions doesn't require workqueue structure defined. These functions uses kernel-global work queue. So, no need to pass workqueue_struct in the argument list.

int schedule_work (struct work_struct *):
int schedule_work_on (int cpu, struct work_struct *):
int scheduled_delayed_work (struct delayed_work *, unsigned long delay);
int scheduled_delayed_work_on (int cpu, struct delayed_work *, unsigned long delay);

Cancel work

/* terminate work in the queue, which is not already executing in the handler */
int cancel_work_sync (struct work_struct *); 
int cancel_delayed_work_sync (struct delayed_work *);

Flush work

Below functions are used to flush the work and works in the specified workqueue.
/* Flush a particular work and block until it is completed */
int flush_work (struct work_struct *);
/* Flush all works in given workqueue and block until it is completed */
int flush_workqueue (struct workqueue_struct *);
/* Flush  kernel-global work queue */
void flush_scheduled_work (void);

Status of work

We can use below two functions to know whether the given work is pending i.e. its handler function is not yet started.
work_pending(work);
delayed_work_pending (work);

Next: Will share running examples for Tasklet and work queues.

You might also like

Related Posts Plugin for WordPress, Blogger...