Extindere kernel FreeBSD cu Loadable Kernel Modules

LKM = Loadable Kernel Modules, KLD = Dynamic Kernel Linker Facility


Exista doua tipuri de kernel: monolithic si micro

Am avut nevoie de extinderea kernelului asa ca am folosit un monolithic (acesta fiind un kernel modular – permite incarcarea functionalitatilor noi in timp real) si nu un micro (kernel care trebuie compilat la fiecare modificare)

Pentru a scrie un modul de kernel BSD am avut nevoie de FreeBSD, versiunea amd64 (suport x86 si x64 atat pe intel cat si pe amd) si NU versiunea i386 (se refera la procesoarele Intel 386), instalata intr-o masina virtuala.

Dupa instalarea completa a FreeBSD-ului am facut update la managerul de pachete (pkg), asemanator cu apt-get din linux astfel:

pkg
pkg update
pkg upgrade

Dupa ce am facut update la pkg putem sa incepem sa scriem efectiv modulul in C. Am preferat sa ma folosesc de Xcode pentru asta si nu de editoarele din linia de comanda precum EE sau NANO asa ca am descarcat XAMP, l-am instalat pe local si am pornit un server pentru a putea transfera usor fisiere intre cele doua calculatoare (macbook-ul si masina virtuala). Am scris modulul integral in Xcode dupa care l-am pus pe server si l-am descarcat din masina virtuala.

Construirea lui efectiva e destul de simpla:

  1. In fisierul C:
    1. Includem librariile necesare
    2. Definim un EventHandler care va reactiona la load sau unload
    3. Definim o structura care va specifica numele modulului si va pastra un pointer catre functia EventHandler
    4. Acum trebuie sa declaram ca tocmai am definit un modul, specificand numele modulului, structura de la pct 3, tipul de interfata pe care va rula modulul (ex: pentru un driver SI_SUB_DRIVERS, pentru un modul care e incarcat la runtime SI_SUB_EXEC) si, in final, ordinea de incarcare a modulului (ex: SI_ORDER_MIDDLE)
  2. Vom avea nevoie de un Makefile in care specificam:
    1. Numele modului
    2. Fisierul sursa
    3. Includem bsd.kmod.mk pentru a sti make ca este vorba despre un modul de kernel

 

//1
#include <sys/types.h>
#include <sys/module.h>
#include <sys/systm.h> // contine functia uprintf. aceasta va face afisarea pe ecran iar printf este folosita pentru log-uri
#include <sys/errno.h>
#include <sys/param.h> // contine define-uri necesare in kernel.h
#include <sys/kernel.h> // contine tipurile de date necesare unui modul

//2
static int EventHandler(struct module *Module, int Event, void *Arg)
{
        int errorCode = 0;

        switch (Event)
        {
                case MOD_LOAD:
                        uprintf("Modulul a fost incarcat...\n");
                        break;
                case MOD_UNLOAD:
                        uprintf("Modulul a fost oprit...\n");
                        break;
                default:
                        errorCode = EOPNOTSUPP;
                        break;
        }

        return(errorCode);
}

//3
static moduledata_t moduleData =
{
        "myFirstKModule", // numele modulului
        EventHandler, // pointer catre functia de mai sus
        NULL // date suplimentare
};

//4
DECLARE_MODULE(myFirstKModule, moduleData, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
# Numele modulului
KMOD = myFirstKModule

# Fisierul sursa
SRCS = myfirst_kmodule.c

# Includem bsd.kmod.mk
.include <bsd.kmod.mk>

Acum am terminat de scris modulul. Mai ramane doar sa il incarcam. Cum facem asta?
Vom folosi un tool foarte tare din bsd, numit Dynamic Kernel Linker Facility (comanda: KLD) care ne permite sa facem load / unload asupra modulelor de kernel sau chiar sa vedem ce module sunt deja incarcate. De retinut: kernelul in sine nu poate fi supus unei operatii de unload

Cum incarcam modulul myFirstKModule?

  1. Vom compila fisierul .c cu ajutorul comenzii make care, datorita includerii bsd.kmod.mk, pe langa myfirst_kmodule.o imi va crea si un fisier myfirst_kmodule.ko. Pe cel din urma il vom trimite catre KLD pentru a-l incarca
  2. Incarcam fisierul myfirst_kmodule.ko cu ajutorul comenzii kldload

 


make
kldload ./myFirstKModule.ko

 

Acum, pe langa mesajul afisat la Load, putem vedea ca modulul a fost incarcat cu ajutorul comenzii kldstat

 

Pentru oprirea unui modul vom folosi comanda kldunload


kldunload myFirstKModule

 

De retinut:

There are six main things LKMs are used for:

  • Device drivers. A device driver is designed for a specific piece of hardware. The kernel uses it to communicate with that piece of hardware without having to know any details of how the hardware works. For example, there is a device driver for ATA disk drives. There is one for NE2000 compatible Ethernet cards. To use any device, the kernel must contain a device driver for it.

 

  • Filesystem drivers. A filesystem driver interprets the contents of a filesystem (which is typically the contents of a disk drive) as files and directories and such. There are lots of different ways of storing files and directories and such on disk drives, on network servers, and in other ways. For each way, you need a filesystem driver. For example, there’s a filesystem driver for the ext2 filesystem type used almost universally on Linux disk drives. There is one for the MS-DOS filesystem too, and one for NFS.

 

  • System calls. User space programs use system calls to get services from the kernel. For example, there are system calls to read a file, to create a new process, and to shut down the system. Most system calls are integral to the system and very standard, so are always built into the base kernel (no LKM option). But you can invent a system call of your own and install it as an LKM. Or you can decide you don’t like the way Linux does something and override an existing system call with an LKM of your own.

 

  • Network drivers. A network driver interprets a network protocol. It feeds and consumes data streams at various layers of the kernel’s networking function. For example, if you want an IPX link in your network, you would use the IPX driver.

 

  • TTY line disciplines. These are essentially augmentations of device drivers for terminal devices.

 

  • Executable interpreters. An executable interpreter loads and runs an executable. Linux is designed to be able to run executables in various formats, and each must have its own executable interpreter.

 

SOURCE: http://www.tldp.org/HOWTO/Module-HOWTO/x73.html

Share Button

Marius

Leave a Reply

Your email address will not be published. Required fields are marked *