Linux 커널 모듈 프로그래밍: Hello World 프로그램

커널 모듈은 요청 시 커널에 로드 및 언로드할 수 있는 코드 조각입니다. 시스템을 재부팅할 필요 없이 커널 기능을 확장합니다. 두 가지 방법을 통해 사용자 정의 코드를 Linux 커널에 추가할 수 있습니다.
  • 기본적인 방법은 커널 소스 트리에 코드를 추가하고 커널을 다시 컴파일하는 것입니다.
  • 보다 효율적인 방법은 커널이 실행되는 동안 커널에 코드를 추가하는 것입니다. 이 프로세스를 모듈 로드라고 합니다. 여기서 모듈은 커널에 추가하려는 코드를 나타냅니다.
런타임에 이러한 코드를 로드하고 공식 Linux 커널의 일부가 아니기 때문에 이를 기본 커널과 다른 로드 가능한 커널 모듈(LKM)이라고 합니다. 기본 커널은 /boot 디렉토리에 있으며 시스템을 부팅할 때 항상 로드되는 반면, LKM은 기본 커널이 이미 로드된 후에 로드됩니다. 그럼에도 불구하고 이러한 LKM은 커널의 많은 부분을 차지하며 기능을 완료하기 위해 기본 커널과 통신합니다. LKM은 다양한 작업을 수행할 수 있지만 기본적으로 세 가지 주요 범주로 분류됩니다.
  • 장치 드라이버
  • 파일 시스템 드라이버 및
  • 시스템 호출.
그렇다면 LKM은 어떤 이점을 제공합니까? 한 가지 주요 이점은 새 장치를 추가하거나 기존 장치를 업그레이드할 때마다 커널을 계속 재구축할 필요가 없다는 것입니다. 이는 시간을 절약하고 기본 커널 오류를 방지하는 데에도 도움이 됩니다. 유용한 경험 법칙은 일단 작동 중인 기본 커널이 있으면 기본 커널을 변경해서는 안 된다는 것입니다. 또한 시스템 문제를 진단하는 데 도움이 됩니다. 예를 들어, 기본 커널에 모듈을 추가했고(즉, 기본 커널을 다시 컴파일하여 수정함) 모듈에 버그가 있다고 가정합니다. 이로 인해 시스템 부팅 시 오류가 발생하고 커널의 어느 부분이 문제를 일으키는지 결코 알 수 없습니다. 반면에 런타임에 모듈을 로드하여 문제가 발생하면 문제를 즉시 알 수 있으며 문제를 해결할 때까지 모듈을 언로드할 수 있습니다. LKM은 단일 명령줄로 로드 및 언로드할 수 있다는 점에서 매우 유연합니다. 이는 필요할 때만 LKM을 로드하므로 메모리를 절약하는 데 도움이 됩니다. 게다가 둘 중 하나를 호출하는 것은 단순히 메모리의 다른 부분에서 코드를 로드하는 것이므로 기본 커널보다 느리지 않습니다. **경고: LKM은 사용자 공간 프로그램이 아닙니다. 그것들은 커널의 일부입니다. 그들은 시스템을 자유롭게 실행할 수 있으며 쉽게 충돌할 수 있습니다. 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 world  n  '  );      return     0  ;   }   static     void     __exit     hello_end  (  void  )   {      printk  (  KERN_INFO     'Goodbye Mr.  n  '  );   }   module_init  (  hello_start  );   module_exit  (  hello_end  );   
위 코드에 대한 설명: 커널 모듈에는 모듈이 커널에 삽입될 때 호출되는 '시작'(초기화) 함수인 init_module()과 모듈이 rmmoded되기 직전에 호출되는 cleanup_module()이라는 '종료'(정리) 함수라는 두 가지 이상의 함수가 있어야 합니다. 실제로 커널 2.3.13부터 상황이 변경되었습니다. 이제 모듈의 시작 및 종료 기능에 원하는 이름을 사용할 수 있습니다. 실제로는 새로운 방법이 선호되는 방법입니다. 그러나 많은 사람들이 여전히 시작 및 종료 기능에 init_module() 및 cleanup_module()을 사용합니다. 이 코드에서는 hello_start()를 초기화 함수로 사용하고 hello_end()를 정리 함수로 사용했습니다. 또 다른 점은 printf() 함수 대신 printk()를 사용했다는 것입니다. 이는 모듈이 콘솔에 아무 것도 인쇄하지 않지만 /var/log/kern.log에 메시지를 기록하기 때문입니다. 따라서 커널 모듈을 디버깅하는 데 사용됩니다. 또한 printk()를 사용하는 동안 필요한 헤더에 정의된 8개의 가능한 로그 수준 문자열이 있습니다. 심각도가 낮은 순서로 나열했습니다.
  • KERN_EMERG: 일반적으로 충돌 이전의 긴급 메시지에 사용됩니다.
  • KERN_ALERT: 즉각적인 조치가 필요한 상황입니다.
  • KERN_CRIT: 심각한 하드웨어 또는 소프트웨어 오류와 관련된 심각한 조건입니다.
  • KERN_ERR: 오류 조건을 보고하는 데 사용됩니다. 장치 드라이버는 종종 KERN_ERR을 사용하여 하드웨어 문제를 보고합니다.
  • KERN_WARNING: 그 자체로는 시스템에 심각한 문제를 일으키지 않는 문제 상황에 대한 경고입니다.
  • KERN_NOTICE: 정상이지만 여전히 주목할 만한 상황입니다. 이 수준에서는 다양한 보안 관련 조건이 보고됩니다.
  • KERN_INFO: 정보 메시지. 많은 드라이버가 이 수준에서 시작 시 찾은 하드웨어에 대한 정보를 인쇄합니다.
  • KERN_DEBUG: 메시지 디버깅에 사용됩니다.
  • KERN_INFO를 사용하여 메시지를 인쇄했습니다. 코드 실행을 위한 시스템 준비: 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:
    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  
    **참고: Makefile의 탭 공백을 잊지 마세요. 모듈 컴파일 및 로드: 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  
    모듈 테스트: 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.