logo

„Linux“ branduolio modulio programavimas: „Hello World“ programa

Branduolio moduliai yra kodo dalys, kurias pagal poreikį galima įkelti ir iškrauti į branduolį. Jie išplečia branduolio funkcionalumą, nereikia iš naujo paleisti sistemos. Pasirinktinius kodus galima pridėti prie „Linux“ branduolių dviem būdais.
  • Pagrindinis būdas yra įtraukti kodą į branduolio šaltinio medį ir perkompiliuoti branduolį.
  • Veiksmingesnis būdas tai padaryti yra pridėti kodą į branduolį, kol jis veikia. Šis procesas vadinamas modulio įkėlimu, kur modulis nurodo kodą, kurį norime pridėti prie branduolio.
Kadangi šiuos kodus įkeliame vykdymo metu ir jie nėra oficialaus Linux branduolio dalis, jie vadinami įkeliamu branduolio moduliu (LKM), kuris skiriasi nuo pagrindinio branduolio. Bazinis branduolys yra /boot kataloge ir visada įkeliamas, kai paleidžiame savo kompiuterį, o LKM įkeliami po to, kai jau įkeliamas pagrindinis branduolys. Nepaisant to, šie LKM yra mūsų branduolio dalis ir bendrauja su baziniu branduoliu, kad atliktų savo funkcijas. LKM gali atlikti įvairias užduotis, tačiau iš esmės jie skirstomi į tris pagrindines kategorijas
  • įrenginio tvarkyklė
  • failų sistemos tvarkyklė ir
  • Sisteminiai skambučiai.
Taigi kokį pranašumą siūlo LKM? Vienas iš pagrindinių jų pranašumų yra tai, kad mums nereikia nuolat kurti branduolio kaskart, kai pridedame naują įrenginį arba atnaujiname seną įrenginį. Tai taupo laiką ir padeda išlaikyti pagrindinio branduolio klaidų. Naudinga nykščio taisyklė yra ta, kad neturėtume keisti savo bazinio branduolio, kai turime veikiantį bazinį branduolį. Taip pat tai padeda diagnozuoti sistemos problemas. Pavyzdžiui, tarkime, kad į pagrindinį branduolį įtraukėme modulį (t. y. modifikavome savo bazinį branduolį, jį perkompiliuodami), o modulyje yra klaida. Tai sukels sistemos įkrovos klaidą ir niekada nesužinosime, kuri branduolio dalis sukelia problemų. Tuo tarpu jei įkelsime modulį vykdymo metu ir tai sukels problemų, mes iš karto sužinosime problemą ir galėsime iškrauti modulį, kol ją ištaisysime. LKM yra labai lankstūs ta prasme, kad juos galima įkelti ir iškrauti naudojant vieną komandų eilutę. Tai padeda sutaupyti atminties, nes įkeliame LKM tik tada, kai mums jų reikia. Be to, jie nėra lėtesni už bazinį branduolį, nes iškvietus kurį nors iš jų tiesiog įkeliamas kodas iš kitos atminties dalies. **Įspėjimas: LKM nėra vartotojo erdvės programos. Jie yra branduolio dalis. Jie gali laisvai paleisti sistemą ir gali lengvai ją sugadinti. 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); 
Aukščiau pateikto kodo paaiškinimas: Branduolio moduliai turi turėti bent dvi funkcijas: funkciją „start“ (inicializacija), vadinamą init_module(), kuri iškviečiama, kai modulis įtraukiamas į branduolį, ir „pabaigos“ (išvalymo) funkcija, vadinama cleanup_module(), kuri iškviečiama prieš pat rmmoded. Tiesą sakant, viskas pasikeitė, pradedant branduoliu 2.3.13. Dabar galite naudoti bet kokį pavadinimą modulio pradžios ir pabaigos funkcijoms. Tiesą sakant, naujasis metodas yra tinkamiausias. Tačiau daugelis žmonių vis dar naudoja init_module() ir cleanup_module() savo pradžios ir pabaigos funkcijoms. Šiame kode mes naudojome hello_start () kaip init funkciją ir hello_end () kaip valymo funkciją. Kitas dalykas, kurį galbūt pastebėjote, yra tai, kad vietoj funkcijos printf () mes panaudojome printk (). Taip yra todėl, kad modulis nieko nespausdins konsolėje, bet užregistruos pranešimą /var/log/kern.log. Todėl jis naudojamas branduolio moduliams derinti. Be to, antraštėje yra apibrėžtos aštuonios galimos žurnalo lygio eilutės, kurios būtinos naudojant printk(). Mes juos išvardijame mažėjančio sunkumo tvarka:
  • KERN_EMERG: naudojamas avariniams pranešimams, paprastai tiems, kurie siunčiami prieš avariją.
  • KERN_ALERT: situacija, kai reikia nedelsiant imtis veiksmų.
  • KERN_CRIT: kritinės sąlygos, dažnai susijusios su rimtais aparatinės ar programinės įrangos gedimais.
  • KERN_ERR: naudojamas pranešti apie klaidų sąlygas; įrenginių tvarkyklės dažnai naudoja KERN_ERR, kad praneštų apie aparatinės įrangos problemas.
  • KERN_WARNING: įspėjimai apie problemines situacijas, kurios savaime nesukelia rimtų sistemos problemų.
  • KERN_NOTICE: situacijos, kurios yra normalios, bet vis tiek vertos dėmesio. Šiame lygyje pranešama apie daugybę su saugumu susijusių sąlygų.
  • KERN_INFO: informaciniai pranešimai. Daugelis tvarkyklių spausdina informaciją apie aparatinę įrangą, kurią randa paleidimo metu šiuo lygiu.
  • KERN_DEBUG: naudojamas pranešimų derinimui.
  • Pranešimui spausdinti naudojome KERN_INFO. Sistemos paruošimas paleisti kodą: 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 šaltinio kodui kompiliuoti:
    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 
    **Pastaba: nepamirškite Makefile skirtukų tarpų Modulio kompiliavimas ir įkėlimas: 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 
    Modulio testavimas: 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.