teaser

How to create a new module ?

Modules in STOS behave mostly like modules in the Linux kernel. Is is an object file with special sections that contains metadata about itself, like its dependancies, its exposed APIs, and things like that. Here we will see how to create such modules.

A Simple module hello.ko

Let’s start by creating a simple module, that just display some output inside on the kernel log.

In order to have a working module, we need to see first how to compile it inside the STOS tree.

There is 2 possible place to put a module:

  • inside the kernel/module directory, for arch-independant modules,
  • or inside kernel/arch/$ARCH/ directory, for arch-dependant modules.

Since hello.ko will only output stuff on the screen, it will belong into the kernel/modules directory. We will need to create the module, and then hook it into the rest of the build system.

let’s create a new directory inside kernel/modules for our module:

$ mkdir $SRC/kernel/modules/hello

Inside it, we will need a Makefile and a simple C file:

# $SRC/kernel/modules/hello/Makefile
CUR_DIR			:= kernel/modules/hello/

OBJS			:= hello.o	# here we need to place all the 
					# object files needed for the module.
MOD-$(CONFIG_HELLO)	:= hello.ko

include $Omk/module.mk

/* $SRC/kernel/modules/hello/hello.c */
#include <kernel/klog.h>
#include <kernel/module.h>
#include <kernel/stos.h>

static void __init_once lol(void)
{
	klog("Init once Hello World !\n");
}

static void __init init(void)
{
	klog("Hello World !\n");
}

MODINFO {
	module_name("hello"),
	module_init(init),
	module_init_once(lol)
};

In order to have it builded, we need to add it to the rest of the build system, quite simple, we just need to edit $(SUBDIRS) var inside kernel/modules/Makefile. Attention, you MUST add it before the init/ modules, due to dependancies issues.

Last part, add into the build config file the line to activate the compilation of the module:

$ echo "CONFIG_HELLO := M" >> $BUILD/stos-config

After all that we will have a working module inside STOS.

More on the MODINFO section

Let’s now have a little explanation about the MODINFO part. It describe all the metadata we need for a module. The definitions of all the entries are inside kernel/include/kernel/module.h header.

The MODINFO macro is in fact an hidden declaration of a variable of type struct modinfo. What we can feed it is :

  • module_name("<module_name>"): the name of the module
  • module_type(<enum module_type>): the type of the module, more on that later.
  • module_deps(<ORed values of enum module_type>): dependancies of the module.
  • module_init(<function>): per-cpu init function (per-cpu, launch 1 time per-cpu.)
  • module_init_once(<function>): init function (global, launch only 1 time.)

module types and exported symbols

The module_type() describe the kind of APIs that the module expose to other through the EXPORT_SYMBOL() macro.

Let’s take a simple example:

I have a module module-a that expose a foo() function, and a module-b that need to use it.

our module-a will need to export the function:

int foo(void)
{
	return 0;
}
EXPORT_SYMBOL(foo);

And in order to have the dependancy mechanism load it at the right time for module-b to start, we need to explain the dependancy:

First add a module_type() into the MODINFO of module-a and the dependancy inside module-b:

/* inside module-a */
MODINFO {
	module_name("module-a"),
	module_type(M_FOO)
};

/* inside module-b */
MODINFO {
	module_name("module-b"),
	module_deps(M_FOO)
};

And here we are, we can call a function from one module to another. In practice, a module can have multiple dependencies, and multiple types.