Skip to content

Latest commit

 

History

History
189 lines (159 loc) · 8.61 KB

커널 모듈.md

File metadata and controls

189 lines (159 loc) · 8.61 KB
  • 모듈은 요청 시 커널에 로드 및 언로드할 수 있는 코드 조각이다.

  • 시스템을 재부팅할 필요 없이 커널의 기능을 확장한다.

    • 예를 들어, 한 가지 유형의 모듈은 커널이 시스템에 연결된 하드웨어에 액세스할 수 있도록 하는 디바이스 드라이버이다.
    • 모듈이 없으면 모놀리식 커널을 빌드하고 커널 이미지에 직접 새로운 기능을 추가해야 하고, 새로운 기능을 원할 때마다 커널을 다시 빌드 및 재부팅해야 한다는 단점이 있다.
    • 따라서 모듈을 이용하면 커널 컴파일 시간을 단축할 수 있다.
  • 로드 가능한 커널 모듈(LKM, Loadable Kernel Module)은 런타임에 Linux 커널에 코드를 추가하거나 제거하는 메커니즘이다.

    • 모듈 없이 Linux 커널에 코드를 추가하려는 경우 가장 기본적인 방법은 커널 소스 트리에 일부 소스 코드 또는 파일을 추가하고 커널을 다시 컴파일하는 것이다.
    • 모듈을 사용하면 Linux 커널이 실행되는 동안 코드를 추가할 수 있다.
      • 이러한 방식으로 추가하는 코드 덩어리를 로드 가능한 커널 모듈이라고 한다.
    • 모듈은 커널이 하드웨어와 통신할 수 있도록 하는 디바이스 드라이버에 이상적이다.
      • 모듈은 /lib/modules/ 디렉터리에서 .ko(kernel object, 커널 개체) 확장자를 가진 파일로 나타낼 수 있다.
      • 디바이스 드라이버는 모듈 형태로 구성되어 있다.
      • 파일 시스템, 메모리 매니지먼트 또한 커널 형태로 구성할 수 있다.
  • 요약: KCM은 모듈별 빌드가 가능하도록 하여 컴파일 시간을 최소화한다.

명령어

  • lsmod

    • 현재 설치된 사용중인 모듈을 보여준다.
    • lsmod 명령은 현재 커널에 설치된 모듈을 나열하는 데 사용할 수 있다.
    • 결과는 모듈의 이름, Size 및 usage(Used by) 목록이다.
      • "Used by"(usage)는 이 모듈을 사용하는 다른 모듈의 수를 의미한다.
    $ lsmod
        Module                  Size  Used by
        udp_diag               16384  0
        raw_diag               16384  0
        unix_diag              16384  0
        ...
  • insmod

    • 모듈을 삽입하기 위해 사용하는 명령이다.
    • insmod(또는 insert module, 모듈 삽입) 명령을 사용하여 커널에 모듈을 삽입할 수 있다.
    • 사용자가 런타임에 커널 모듈을 로드하여 커널 기능을 확장할 수 있다.
    • insmod my_module.ko -> 커널 개체 파일(.ko)을 커널에 삽입한다.
  • rmmod

    • 모듈을 제거할 때 사용하는 명령이다.
    • rmmod(또는 remove module, 모듈 제거) 명령은 실행 중인 커널에서 로드 가능한 모듈을 언로드한다.
    • 모듈을 삭제하기 위해선 사용 중이 아니어야 하고, 다른 모듈에서 참조하지 않아야 한다.
    • 명령줄에서 둘 이상의 모듈 이름이 지정되면 해당 모듈은 지정된 순서대로 제거된다.
    • 이것은 스택된 모듈의 언로드를 지원한다.
  • modinfo

    • 모듈 정보를 얻으려고 할 때 사용하는 명령이다.

    • Linux 시스템에서 modinfo 명령은 Linux 커널 모듈에 대한 정보를 표시하는 데 사용된다.

    • 이 명령은 명령줄에 제공된 Linux 커널 모듈에서 정보를 추출한다.

      $ modinfo udp_diag 
          filename:       /lib/modules/5.15.0-1019-aws/kernel/net/ipv4/udp_diag.ko
          alias:          net-pf-16-proto-4-type-2-136
          alias:          net-pf-16-proto-4-type-2-17
          license:        GPL
          srcversion:     A6913F04E5CF94B0DEC8CAB
          depends:        inet_diag
          retpoline:      Y
          intree:         Y
          name:           udp_diag
          vermagic:       5.15.0-1019-aws SMP mod_unload modversions 
          sig_id:         PKCS#7
  • modprobe

    • 모듈을 설치/삭제하는 명령어

    • insmod/rmmod 명령어와 다르게 modules.dep 파일을 참조해 의존성 문제를 해결

      $ modprobe --help
      Usage:
          modprobe [options] [-i] [-b] modulename
          modprobe [options] -a [-i] [-b] modulename [modulename...]
          modprobe [options] -r [-i] modulename
          modprobe [options] -r -a [-i] modulename [modulename...]
          modprobe [options] -c
          modprobe [options] --dump-modversions filename
      Management Options:
          -a, --all                   Consider every non-argument to
                                      be a module name to be inserted
                                      or removed (-r)
          -r, --remove                Remove modules instead of inserting
              --remove-dependencies   Also remove modules depending on it
  • depmod

    • 의존성을 검사하여 modules.dep 파일을 갱신하는 명령어

      $ depmod --help
      Usage:
          depmod -[aA] [options] [forced_version]
      
      If no arguments (except options) are given, "depmod -a" is assumed
      
      depmod will output a dependency list suitable for the modprobe utility.

커널 모듈 만들기

  • 모듈의 소스 코드는 커널 소스 트리 밖에 있을 수 있다.
  • 모듈 소스 디렉토리에 메이크파일을 넣는다.
  • 컴파일 후 컴파일된 모듈은 확장자가 .ko인 파일이다.

Makefile 생성

  • $ vi Makefile

      ```bash
      #------Makefile------#
      obj-m := hello_module.o
      KERNEL_DIR := /lib/modules/$(shell uname -r)/build
      PWD := $(shell pwd)
      default:
        $(MAKE) -C $(KERNAL_DIR) SUBDIR=${PWD} modules
      clean:
        $(MAKE) -C $(KERNAL_DIR) SUBDIR=${PWD} clean
       ```
    
    • 오브젝트 모듈:= hello_module.o
      • 컴파일할 모듈의 이름을 넣으면 된다.
    • KERNEL_DIR := /lib/modules/$(shell uname -r)/build
      • 커널 디렉토리
      • shell uname : 커널 버전이 나온다.
      • 커널 버전에 맞는 빌드 디렉토리를 넣어야 한다.
    • PWD := $(shell pwd)
      • 소스코드가 있는 디렉토리
      • Print Working Directory
    • default : $(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules
      • default는 뒤에 아무 옵션을 주지 않았을 때 시행되는 명령어이다.
      • 커널 디렉토리와 서브 디렉토리를 넣어준다.
      • 모듈 컴파일이니 modules를 붙인다.
    • clean : $(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) clean
      • clean: make clean 썼을 때 시행되는 명령어이다.

커널 모듈 작성

#--------- hello_module.c ---------#
#include <linux/kernel.h> //Needed by all modules
#include <linux/module.h> //Needed for KERN_ALERT
#include <linux/init.h> //Needed for the macros

int __init hello_module_init(void)
{
	printk("Hello Module!\n");
	return 0;
}

void __exit hello_module_cleanup(void)
{
	printk("Bye Module!\n");
}

module_init(hello_module_init); 
module_exit(hello_module_cleanup); 
MODULE_LICENSE("GPL");
  • .c 파일을 만들어 세 가지 커널 헤더를 include한다.

  • insmod는 해당 모듈을 로드한다. 파일의 module_init 함수를 부른다.

  • rmmod는 해당 모듈을 언로드한다. 파일의 module_exit 함수를 부른다.

  • 모듈 초기화 및 종료

    • module_init(hello_module_init)
      • 초기화 진입점
      • 모듈 삽입 시 실행할 함수 (hello_module_init)
      • hello_module_init()는 모듈을 로드할 때 호출된다.
    • module_exit(hello_module_cleanup)
      • 출구 진입점
      • 모듈 제거 시 실행할 함수(hello_module_cleanup)
      • hello_module_cleanup()은 모듈을 언로드할 때 호출된다.
  • 커널 모듈에는 최소한 두 가지 함수가 있어야 한다.

    • 모듈이 커널에 insmod될 때 호출되는 "시작"(initialization) 함수(예: hello_module_init())
    • 모듈이 커널에 rmmod될 때 호출되는 "종료"(cleanup) 함수(예: hello_module_cleanup())
  • 커널 모듈 시작

    • 커널 코드를 실행하기 때문에 루트 권한이 필요하다.
    • insmod로 커널 모듈을 로드해야 한다.
      • insmod hello_module.ko (반드시 .ko를 붙여야 한다.)
      • 모듈이 로드되고 초기화 함수가 실행된다.
    • 모듈은 특정 커널 버전에 대해 컴파일되며 다른 커널에는 로드되지 않는다.
    • rmmod로 모듈 제거
      • rmmod hello_module 또는 rmmod hello_module.ko
      • 언로드 전에 모듈 종료 함수가 호출된다.