Creating an Embedded Linux Kernel Module for System Info, Study Guides, Projects, Research of Computer Science

Information about a programming project for creating a loadable kernel module (lkm) for embedded linux using the accelent idp platform. The project involves writing a simple lkm to read and write to the basic system information (uname) on linux 2.4. Partial pseudo code and a makefile to help complete the project. The goal is to learn how to read and write to system parameters dynamically after the system has been booted.

Typology: Study Guides, Projects, Research

Pre 2010

Uploaded on 09/02/2009

koofers-user-0ng
koofers-user-0ng 🇺🇸

10 documents

1 / 8

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
cse591
Embedded Linux
Loadable Kernel Module
Programming Project
Preliminary Project Data April 14, 2008
Spring 2008
Using the /proc File System to Read and Write a Kernel Data Structure
This project involves writing a loadable kernel module (LKM) for the Accelent IDP Embedded
Linux ARM platform that enables you to tune kernel parameters. Let us say, you have some
device specific parameters in a parport driver which you want to configure dynamically after the
system has been booted and your driver is loaded, then you can write a simple kernel module like
the one you will learn to do in this project and be able to read and write to the parameters.
In this project, you are provided with the source file containing a template of all the function
definitions and a Makefile. The file also contains partial pseudo code to help you complete the
program. The basic system information on your Linux box is usually stored in the
system_utsname structure. This information can be peeked into using the uname command. Refer
to the manual page of uname for more information. The embedded board you will be testing has
already been installed with linux kernel 2.4.18. This project is to be run after you have run the
elpp4 and elpp5 projects. The partial source code for the LKM module file procfs_sysinfo.c and a
complete Makefile are given below:
procfs_sysinfo.c
/*
* procfs_sysinfo.c
* The following program demonstrates how to interface with /proc.
* Thru' this simple loadable module example, we show how to read and
* write to the basic System information(uname) on Linux 2.4.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
/*
* THIS_MODULE is a pointer to this module, in other words pointer to
* this module and owns the text and data of this module.
*/
#define THIS_MODULE (&__this_module)
MODULE_DESCRIPTION("Kernel Module to read/write System information.");
MODULE_AUTHOR("Sreenivasa");
#define MODULE_NAME "your_modulename"
#define MODULE_VERSION "1.0"
static int proc_read_sysname(char *page, char **start,
off_t off, int count,
int *eof, void *data)
{
/*
* Write the necessary code to copy the sysname to user space.
*/
pf3
pf4
pf5
pf8

Partial preview of the text

Download Creating an Embedded Linux Kernel Module for System Info and more Study Guides, Projects, Research Computer Science in PDF only on Docsity!

cse

Embedded Linux

Loadable Kernel Module

Programming Project

Preliminary Project Data April 14, 2008

Spring 2008

Using the /proc File System to Read and Write a Kernel Data Structure

This project involves writing a loadable kernel module (LKM) for the Accelent IDP Embedded

Linux ARM platform that enables you to tune kernel parameters. Let us say, you have some

device specific parameters in a parport driver which you want to configure dynamically after the

system has been booted and your driver is loaded, then you can write a simple kernel module like

the one you will learn to do in this project and be able to read and write to the parameters.

In this project, you are provided with the source file containing a template of all the function

definitions and a Makefile. The file also contains partial pseudo code to help you complete the

program. The basic system information on your Linux box is usually stored in the

system_utsname structure. This information can be peeked into using the uname command. Refer

to the manual page of uname for more information. The embedded board you will be testing has

already been installed with linux kernel 2.4.18. This project is to be run after you have run the

elpp4 and elpp5 projects. The partial source code for the LKM module file procfs_sysinfo.c and a

complete Makefile are given below:

procfs_sysinfo.c

  • procfs_sysinfo.c
  • The following program demonstrates how to interface with /proc.
  • Thru' this simple loadable module example, we show how to read and
  • write to the basic System information(uname) on Linux 2.4.

/ #include #include #include #include #include #include /

  • THIS_MODULE is a pointer to this module, in other words pointer to
  • this module and owns the text and data of this module. */ #define THIS_MODULE (&__this_module) MODULE_DESCRIPTION("Kernel Module to read/write System information."); MODULE_AUTHOR("Sreenivasa"); #define MODULE_NAME "your_modulename" #define MODULE_VERSION "1.0" static int proc_read_sysname(char *page, char **start, off_t off, int count, int *eof, void data) { /
  • Write the necessary code to copy the sysname to user space. */

cse

Embedded Linux

Loadable Kernel Module

Programming Project

Spring 2008

static int proc_write_sysname(struct file *file, const char *buffer, unsigned long count, void data) { /

  • Write the necessary code to copy the sysname from user space. */ } static int proc_read_nodename(char *page, char **start, off_t off, int count, int *eof, void data) { /
  • Write the necessary code to copy the nodename to user space. */ } static int proc_write_nodename(struct file *file, const char *buffer, unsigned long count, void data) { /
  • Write the necessary code to copy the nodename from user space. */ } static int proc_read_release(char *page, char **start, off_t off, int count, int *eof, void data) { /
  • Write the necessary code to copy the release to user space. */ } static int proc_write_release(struct file *file, const char *buffer, unsigned long count, void data) { /
  • Write the necessary code to copy the release from user space. */ } static int proc_read_version(char *page, char **start, off_t off, int count, int *eof, void data) { /
  • Write the necessary code to copy the version to user space. */ }

cse

Embedded Linux

Loadable Kernel Module

Programming Project

Spring 2008

  • initialized, create and initialize the nodename, release,
  • version and machine name directory entries. / / everything OK / printk(KERN_INFO "%s %s initialised\n", MODULE_NAME, MODULE_VERSION); return 0; out: return rv; } static void __exit cleanup_procfs_example(void) { /
  • Remove all the directory entries namely sysname, nodename,
  • release, version, and machine.
  • Finally remove the root directory entry. */ } module_init(init_procfs_example); module_exit(cleanup_procfs_example); EXPORT_NO_SYMBOLS;

Makefile:

This Makefile is to build the object procfs_sysinfo.o module.

The build takes care of any linux version. build the

procfs_sysinfo.o module.

CC=arm-linux-gcc KERNEL_SRC=/usr/src/linux-2.4. CFLAGS=-Wall -O MODFLAGS=-I$(KERNEL_SRC)/include -D__KERNEL__ -DMODULE procfs_sysinfo.o: procfs_sysinfo.c $(CC) $(CFLAGS) $(MODFLAGS) -c procfs_sysinfo.c

cd to modules directory to be in the right environment

In the above Makefile, the KERNEL_SRC path should point to a path where a valid 2.4.

kernel has been downloaded and contains all the source and header files. It is not necessary that

the kernel has to be compiled. The path should exist and contain kernel 2.4.18 sources.

cse

Embedded Linux

Loadable Kernel Module

Programming Project

Spring 2008

procfs_sysinfo.c

Your module should be able to:

1. The init function should be completed as described here. First you will create a root

directory entry, sysinfo and then add the /proc entries for each and every field in the

system_utsname structure under the directory entry sysinfo, in the init routine. Each entry

is actually represented by a file name in the /proc/sysinfo file system.

2. Read and write to every field from the user space. Each entry is created by the interface

create_proc_entry(), and is abstracted by a pointer to structure of type proc_dir_entry. To

be able to do this, you have to initialize the proc entry structures you just created in step

1. Among other things, you will be initializing the read_proc and write_proc fields of this

structure.

Tips to complete the various functions:

 Use sprintf to print the values from the structure in the read routines.

 Use copy_from_user to read data from user space to kernel space and copy it to the

system_utsname structure.

 Use MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros in all the

functions except init and exit functions. The former should be added at the beginning of

the function and latter should be added at the end of the function. These macros ensure

that a module does not get removed when it is in use.

Overview of the kernel interfaces used in this project:

struct proc_dir_entry *create_proc_entry( const char *name, mode_t mode, struct proc_dir_entry *parent);

This kernel function creates an entry in the proc file system with the string in the first field as file

name. For the mode bits see stat.h, for a description of the flags see man stat. The last argument

is the directory in which the proc file is to appear, in this project it will be “/proc/sysinfo”

because we will be creating entries in the parent directory /proc/sysinfo.

The macros __init and __exit are defined in include/linux/init.h:

#define __init _attribute ((section (".text.init"))) #define __exit attribute ((unused, section(".text.exit")))

They tell the compiler to put all of these objects into their own segment called code_segment.

Basically, they tell the compiler to put those functions which have these assembler tags

in .text.init and .text.exit sections respectively.

cse

Embedded Linux

Loadable Kernel Module

Programming Project

Spring 2008

structure. The read_proc and write_proc will be assigned the addresses of read and write callback functions which are explained in the next sub section.

  1. Similar to step 3, nodename, release, version, and machine_name entries are created and their members are initialized properly.

cse

Embedded Linux

Loadable Kernel Module

Programming Project

Spring 2008

cleanup_procfs_example routine:

  1. All the directory entries are removed, namely sysname, nodename, release, version, and machine_name.
  2. Finally the root directory entry, MODULE_NAME is removed. The read_proc and write_proc members of the /proc entries correspond to the read and write callback functions and their generic functionality is explained next.

The Read Callback function

The read function has the following prototype: int module_read(char *page, char **begin, off_t offset, int count, int *eof, void *data) This function serves the purpose of reading data from a /proc entry from the kernel to the user space. The page argument is the location into which you write the data intended for the user, where count defines the maximum number of characters that can be written. The begin and offset arguments are used for returning more than a page of data (typically 4KB). When all the data have been written, the eof (end-of-file) argument is set. data represents private data. The page buffer provided here is in kernel space. Therefore, it is not necessary to invoke copy_to_user for copying the data to page.

The Write callback function

The write function has the following prototype: int module_write(char file *filp, const char *buffer, int count, void *data) This function serves the purpose of writing data from a /proc entry from the kernel to user space. The filp argument is essentially an open file structure (not used in this project). The buffer argument is the string data being passed to kernel space. The buffer address is actually a user-space buffer, so it is not possible to read it directly. The copy_from_user function is used to copy data from user space to kernel. The count argument defines how much data in buffer is being read. The data argument is a pointer to the private data.