logo

Programação do Módulo Kernel Linux: Programa Hello World

Módulos do kernel são pedaços de código que podem ser carregados e descarregados no kernel sob demanda. Eles estendem a funcionalidade do kernel sem a necessidade de reinicializar o sistema. Códigos personalizados podem ser adicionados aos kernels do Linux por meio de dois métodos.
  • A maneira básica é adicionar o código à árvore fonte do kernel e recompilar o kernel.
  • Uma maneira mais eficiente de fazer isso é adicionar código ao kernel enquanto ele está em execução. Este processo é chamado de carregamento do módulo, onde módulo se refere ao código que queremos adicionar ao kernel.
Como estamos carregando esses códigos em tempo de execução e eles não fazem parte do kernel oficial do Linux, eles são chamados de módulo carregável do kernel (LKM), que é diferente do kernel base. O kernel base está localizado no diretório /boot e é sempre carregado quando inicializamos nossa máquina, enquanto os LKMs são carregados depois que o kernel base já está carregado. No entanto, esses LKM fazem parte do nosso kernel e se comunicam com o kernel base para completar suas funções. Os LKMs podem executar uma variedade de tarefas, mas basicamente eles se enquadram em três categorias principais
  • driver de dispositivo
  • driver do sistema de arquivos e
  • Chamadas do sistema.
Então, que vantagem os LKMs oferecem? Uma grande vantagem que eles têm é que não precisamos reconstruir o kernel toda vez que adicionamos um novo dispositivo ou atualizamos um dispositivo antigo. Isso economiza tempo e também ajuda a manter nosso kernel base livre de erros. Uma regra prática útil é que não devemos alterar nosso kernel base uma vez que tenhamos um kernel base funcional. Também ajuda no diagnóstico de problemas do sistema. Por exemplo, suponha que adicionamos um módulo ao kernel base (ou seja, modificamos nosso kernel base recompilando-o) e o módulo contém um bug. Isso causará erros na inicialização do sistema e nunca saberemos qual parte do kernel está causando problemas. Considerando que, se carregarmos o módulo em tempo de execução e ele causar problemas, saberemos imediatamente o problema e poderemos descarregar o módulo até corrigi-lo. Os LKMs são muito flexíveis no sentido de que podem ser carregados e descarregados com uma única linha de comando. Isso ajuda a economizar memória, pois carregamos o LKM somente quando precisamos deles. Além disso, eles não são mais lentos que o kernel base porque chamar qualquer um deles é simplesmente carregar código de uma parte diferente da memória. **Aviso: LKMs não são programas de espaço do usuário. Eles fazem parte do kernel. Eles têm funcionamento livre do sistema e podem travá-lo facilmente. So now that we have established the use loadable kernel modules we are going to write a hello world kernel module. That will print a message when we load the module and an exit message when we unload the module. Code: CPP
/**  * @file hello.c  * @author Akshat Sinha  * @date 10 Sept 2016  * @version 0.1  * @brief An introductory 'Hello World!' loadable kernel  * module (LKM) that can display a message in the /var/log/kern.log  * file when the module is loaded and removed. The module can accept  * an argument when it is loaded -- the name which appears in the  * kernel log files. */ #include  /* Needed by all modules */ #include  /* Needed for KERN_INFO */ #include  /* Needed for the macros */ ///< The license type -- this affects runtime behavior MODULE_LICENSE('GPL'); ///< The author -- visible when you use modinfo MODULE_AUTHOR('Akshat Sinha'); ///< The description -- see modinfo MODULE_DESCRIPTION('A simple Hello world LKM!'); ///< The version of the module MODULE_VERSION('0.1'); static int __init hello_start(void) {  printk(KERN_INFO 'Loading hello module...n');  printk(KERN_INFO 'Hello worldn');  return 0; } static void __exit hello_end(void) {  printk(KERN_INFO 'Goodbye Mr.n'); } module_init(hello_start); module_exit(hello_end); 
Explicação para o código acima: Os módulos do kernel devem ter pelo menos duas funções: uma função de 'início' (inicialização) chamada init_module() que é chamada quando o módulo é inserido no kernel e uma função de 'fim' (limpeza) chamada cleanup_module() que é chamada logo antes de ser modificado. Na verdade as coisas mudaram a partir do kernel 2.3.13. Agora você pode usar qualquer nome que desejar para as funções inicial e final de um módulo. Na verdade, o novo método é o método preferido. No entanto, muitas pessoas ainda usam init_module() e cleanup_module() para suas funções inicial e final. Neste código usamos hello_start() como função init e hello_end() como função de limpeza. Outra coisa que você deve ter notado é que em vez da função printf() usamos printk(). Isso ocorre porque o módulo não imprimirá nada no console, mas registrará a mensagem em /var/log/kern.log. Portanto, é usado para depurar módulos do kernel. Além disso, existem oito strings de nível de log possíveis definidas no cabeçalho que são necessárias ao usar printk(). Nós os listamos em ordem decrescente de gravidade:
  • KERN_EMERG: Usado para mensagens de emergência, geralmente aquelas que precedem uma falha.
  • KERN_ALERT: Uma situação que requer ação imediata.
  • KERN_CRIT: Condições críticas frequentemente relacionadas a falhas graves de hardware ou software.
  • KERN_ERR: Usado para reportar condições de erro; drivers de dispositivo geralmente usam KERN_ERR para relatar dificuldades de hardware.
  • KERN_WARNING: Avisos sobre situações problemáticas que por si só não criam problemas graves no sistema.
  • KERN_NOTICE: Situações normais mas ainda dignas de nota. Várias condições relacionadas à segurança são relatadas neste nível.
  • KERN_INFO: Mensagens informativas. Muitos drivers imprimem informações sobre o hardware que encontram na inicialização neste nível.
  • KERN_DEBUG: Usado para depuração de mensagens.
  • Usamos KERN_INFO para imprimir a mensagem. Preparando o sistema para executar o código: The system must be prepared to build kernel code and to do this you must have the Linux headers installed on your device. On a typical Linux desktop machine you can use your package manager to locate the correct package to install. For example under 64-bit Debian you can use:
    akshat@gfg:~$ sudo apt-get install build-essential linux-headers-$(uname -r) 
    Makefile para compilar o código fonte:
    obj-m = hello.o all: make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 
    **Nota: não se esqueça dos espaços de tabulação no Makefile Compilando e carregando o módulo: Run the make command to compile the source code. Then use insmod to load the module.
    akshat@gfg:~$ make make -C /lib/modules/4.2.0-42-generic/build/ M=/home/akshat/Documents/hello-module modules make[1]: Entering directory `/usr/src/linux-headers-4.2.0-42-generic' CC [M] /home/akshat/Documents/hello-module/hello.o Building modules stage 2. MODPOST 1 modules CC /home/akshat/Documents/hello-module/hello.mod.o LD [M] /home/akshat/Documents/hello-module/hello.ko make[1]: Leaving directory `/usr/src/linux-headers-4.2.0-42-generic' 
    Now we will use insmod to load the hello.ko object.
    akshat@gfg:~$ sudo insmod hello.ko 
    Testando o módulo: You can get information about the module using the modinfo command which will identify the description author and any module parameters that are defined:
    akshat@gfg:~$ modinfo hello.ko filename: /home/akshat/Documents/hello-module/hello.ko version: 0.1 description: A simple Hello world LKM author: Akshat Sinha license: GPL srcversion: 2F2B1B95DA1F08AC18B09BC depends: vermagic: 4.2.0-42-generic SMP mod_unload modversions 
    To see the message we need to read the kern.log in /var/log directory.
    akshat@gfg:~$ tail /var/log/kern.log ... ... Sep 10 17:43:39 akshat-gfg kernel: [26380.327886] Hello world To unload the module we run rmmod: akshat@gfg:~$ sudo rmmod hello Now run the tail command to get the exit message. akshat@gfg:~$ tail /var/log/kern.log ... Sep 10 17:43:39 akshat-gfg kernel: [26380.327886] Hello world Sep 10 17:45:42 akshat-gfg kernel: [26503.773982] Goodbye Mr.