2016-03-16

Linux Kernel Module Makefile 디버깅




정말 간단한 HelloWorld 커널을 모듈하면서, 시행착오가 많았다.
정리하면 소스 자체는 간단하니 문제가 없었지만, Makefile및 환경 설정에서 문제가 많이 발생했다.



  • CASE 1
원인 : 리눅스는 Makefile의 대소문자를 구분한다. 그냥 makefile로 파일을 생성하면
다음과 같은 에러를 얻는다.

# make
make -C /lib/modules/3.10.0-229.el7.x86_64/build SUBDIRS=/root/drivers KBUILD_VERBOSE=0 modules
make[1]: Entering directory `/usr/src/kernels/3.10.0-229.el7.x86_64'
scripts/Makefile.build:44: /root/drivers/Makefile: No such file or directory
make[2]: *** No rule to make target `/root/drivers/Makefile'.  Stop.
make[1]: *** [_module_/root/drivers] Error 2
make[1]: Leaving directory `/usr/src/kernels/3.10.0-229.el7.x86_64'
make: *** [all] Error 2
해결 : 파일이름을 makefile -> Makefile 로 대소문자 구분하도록 수정한다.




  • CASE 2
원인 : 커널 모듈 컴파일시 'make'가 사용하는 모듈 설치 도구가 없는 경우 발생.
나는 CentOS7.1의 기본 커널 버전인 3.10 을 3.14.64 버전으로 업데이트 했는데,
이때 모듈 설치 도구는 컴파일에서 제외되어 있었음.

# make -d
 Successfully remade target file `FORCE'.
   Finished prerequisites of target file `/root/workspace/drivers/src/helloworld.o'.
   Prerequisite `/root/workspace/drivers/src/helloworld.c' is older than target `/root/workspace/drivers/src/helloworld.o'.
   Prerequisite `/usr/src/kernels/linux-3.14.64/scripts/recordmcount.c' is older than target `/root/workspace/drivers/src/helloworld.o'.
   Prerequisite `/usr/src/kernels/linux-3.14.64/scripts/recordmcount.h' is older than target `/root/workspace/drivers/src/helloworld.o'.
   Prerequisite `FORCE' of target `/root/workspace/drivers/src/helloworld.o' does not exist.
  Must remake target `/root/workspace/drivers/src/helloworld.o'.
Invoking recipe from scripts/Makefile.build:314 to update target `/root/workspace/drivers/src/helloworld.o'.
Putting child 0x1267170 (/root/workspace/drivers/src/helloworld.o) PID 78769 on the chain.
Live child 0x1267170 (/root/workspace/drivers/src/helloworld.o) PID 78769 
  CC [M]  /root/workspace/drivers/src/helloworld.o
/bin/sh: /usr/src/kernels/linux-3.14.64/scripts/recordmcount: No such file or directory
Reaping losing child 0x1267170 PID 78769 
make[2]: *** [/root/workspace/drivers/src/helloworld.o] Error 1
Removing child 0x1267170 PID 78769 from chain.
Reaping losing child 0x9cb2d0 PID 78766 
make[1]: *** [_module_/root/workspace/drivers/src] Error 2
Removing child 0x9cb2d0 PID 78766 from chain.
make[1]: Leaving directory `/usr/src/kernels/linux-3.14.64'
Reaping losing child 0x2341fd0 PID 78546 
make: *** [all] Error 2
Removing child 0x2341fd0 PID 78546 from chain.
※ 위의 recordmcount 뿐만 아닐라 모듈 관리에 설치된 툴들이 계속 없다고 설치 중지되므로 다  개별 처리 하거나 한꺼번에 처리 해줘야 한다.

해결 : 모듈 설치 도구를 컴파일해 준다.
개별 컴파일도 가능하다.
# cd /usr/src/kernels/linux-3.14.64
# make modules_prepare
 make[1]: Nothing to be done for `all'.
make[1]: Nothing to be done for `relocs'.
  CHK     include/config/kernel.release
  CHK     include/generated/uapi/linux/version.h
  CHK     include/generated/utsrelease.h
  CALL    scripts/checksyscalls.sh
  HOSTCC  scripts/genksyms/genksyms.o
  SHIPPED scripts/genksyms/lex.lex.c
  SHIPPED scripts/genksyms/keywords.hash.c
  SHIPPED scripts/genksyms/parse.tab.h
  HOSTCC  scripts/genksyms/lex.lex.o
  SHIPPED scripts/genksyms/parse.tab.c
  HOSTCC  scripts/genksyms/parse.tab.o
  HOSTLD  scripts/genksyms/genksyms
  CC      scripts/mod/empty.o
  HOSTCC  scripts/mod/mk_elfconfig
  MKELF   scripts/mod/elfconfig.h
  CC      scripts/mod/devicetable-offsets.s
  GEN     scripts/mod/devicetable-offsets.h
  HOSTCC  scripts/mod/file2alias.o
  HOSTCC  scripts/mod/modpost.o
  HOSTCC  scripts/mod/sumversion.o
  HOSTLD  scripts/mod/modpost
  HOSTCC  scripts/selinux/genheaders/genheaders
  HOSTCC  scripts/selinux/mdp/mdp
  HOSTCC  scripts/kallsyms
  HOSTCC  scripts/pnmtologo
  HOSTCC  scripts/conmakehash
  HOSTCC  scripts/recordmcount
  HOSTCC  scripts/sortextable
  HOSTCC  scripts/asn1_compiler

CentOS 7 : Kernel 3.14 : HelloWorld Module 빌드하기.

CentOS 7 : Kernel 3.14 : HelloWorld Module 빌드하기.
아주 간단한 리눅스 커널 모듈을 만들어 보자.
목표는 모듈 등록과 삭제후 “dmseg | tail”  명령으로 메세지를 확이 할수 있게 하는것이다.

  1. 먼저 커널 모듈을 작성한다.
임의의 디렉토리 “/roor/Desktop/helloworld”에 모듈 소스를 작성한다.

helloworld.c
#include <linux/module.h>
#include <linux/init.h>

static int __init helloworld_init(void)
{
   pr_info("Hello World!\n");
   return 0;
}

static void __exit helloworld_exit(void)
{
   pr_info("Goodby World.\n");
}

module_init(helloworld_init);
module_exit(helloworld_exit);
MODULE_AUTHOR("root");
MODULE_DESCRIPTION("Hello World Module");

※  기타 MODULE_XXXX
: modinfo 명령으로 해당 모듈을 조회시 표현되는 정보들을 등록 한다.
modinfo_list.PNG

※   커널 시스템 메세지 출력
pr_info("Hello World!\n");
을 사용하거나

incude<kernel.h>
printk(“Hello World!\n");
을 사용한다.

    

  1. 커널 모듈을 빌드하기 위한 Makefile 작성

Makefile
KERNEL_DIR := /lib/modules/`uname -r`/build
BUILD_DIR := `pwd`
VERBOSE   := 1

obj-m := helloworld.o

all:
make -C $(KERNEL_DIR) SUBDIRS=$(BUILD_DIR) KBUILD_VERBOSE=$(VERBOSE) modules

clean:
rm -rf  *.o *.ko *.mod.c *.symvers *.order .tmp_versions .helloworld.c.*

※  Makefile 필수 문법.
: Makefile 에서 사용하는 시스템 명령어는 반드시 {TAB}으로 띄어져 있어야 한다.

  1. 커널 모듈을 작성 한다.
# make
make -C /lib/modules/3.14.64/build SUBDIRS=/root/drivers KBUILD_VERBOSE=0 modules
make[1]: Entering directory `/usr/src/kernels/3.14.64'
 CC [M]  /root/drivers/helloworld.o
 Building modules, stage 2.
 MODPOST 1 modules
 CC      /root/drivers/helloworld.mod.o
 LD [M]  /root/drivers/helloworld.ko
make[1]: Leaving directory `/usr/src/kernels/3.14.64'
# ls
helloworld.c   helloworld.mod.c  helloworld.o  Makefile~      Module.symvers
helloworld.ko  helloworld.mod.o  Makefile      modules.order

※  Makefile 디버깅
: maked -d 로 실행 하면 자세한 상황을 확인 할수 있다.
  1. 동작확인

  • 모듈을 커널에 등록.
# insmod helloworld.ko
# echo $?
0

  • 커널에 로드된 모듈을 조회
# lsmod | grep helloworld
helloworld             12430  0

< 모듈 이름>         <모듈이 사용하는 메모리 사이즈 > < 해당 모듈을 참조하는 모듈의 수>

  • 커널 모듈 파일의 정보 조회
# modinfo helloworld.ko
filename:       /root/workspace/drivers/src/helloworld.ko
license:        BSD
description:    Hello World Module
author:         root
srcversion:     EB07C4DCC99CCF81F69125E
depends:        
vermagic:       3.14.64 SMP mod_unload modversions

  • 커널에서 로드된 모듈 삭제
# rmmod helloworld
# echo $?
0

  • 커널 정상 동작 확인
# dmesg | tail
[ 7921.789879] Hello World!
[ 7983.689416] Goodby World.

2016-03-13

리눅스 모듈 vs 디바이스

리눅스 모듈 vs 디바이스


모듈은 다음과 같은 특징을 갖는다.
  1. 설치시 소스 커널소스를 다시 컴파일 하지 않고, 동적으로 추가 삭제 가능하다.
  2. 드라이버를 모듈에 포함 할 수 있다. 주로 이 목적으로 사용한다.
  3. MMU(Memory Management Unit)가 있는 CPU에서만 지원한다.
  4. 모듈 방식은 PNP 방식의 디바이스를 지원하기 위해서는 필수다.


디바이스는 다음과 같은 특징을 갖는다.
  1. 디바이스 파일들은 일반적으로 /dev 디렉토리의 하부에 저장된다.
  2. 디바이스 파일은 타입과 Major,Minor 넘버를 가진다.
  3. mknod를 사용해서 디바이스 파일을 생성한다.
  4. 네트워크 파일시스템이나 , 표준 inode 형식을 지원하지 않는 파일 시스템에는 디바이스 파일을 생성 할 수 없다.

문자 디바이스 Character Device Driver
: 임의의 길이를 갖는 문자열을 다루는 버퍼 없는 디바이스 드라이버
  1. 응용 프로그램은 open(), close(), read(), write() 와 같은 파일 처리 함수를 사용해서 처리한다.
  2. 스트림 지향적으로 사용 할수 있다.
블록 디바이스 Block Device Driver
: 커널의 파일 시스템이 관리하고 버퍼가 있는 디바이스
  1. 응용 프로그램에서 잘 사용하지 않는다.
  2. 디바이스 드라이버는 파일 시스템을 지원하는 구조이므로,  프로그램은 파일 시스템을 통해서 접근한다.
  3. 블록 지향적으로 사용 할수 있다.
  4. 스트림도 지원하지만 필수는 구현은 아니다.
네트워크 디바이스 드라이버 Network Device Driver
 : 네트워크 층에서 사용하는 디바이스 드라이버
  1. 실질적으로 /dev 의 구조에 속하지 않으며, 네트워크 구조체 형식으로 동작 한다. 따라서 파일이 존재 하지 않느다.
  2. 응용 프로그램에서 직접적으로 사용 할수 없다.
  3. 일부 응용 프로그램에서는 시스템 콜을 사용하여 드라이버를 호출, 사용한다.
  4. 블록, 문자 디바이스와는 다르게 파일시스템에 의존하지 않는다.

2016-03-10

새벽의 이별하는 젊은 시인


사람의 이별과 만남은 언제나 감성적이다.
이별을 했나보다.

CentOS 7.1 Kernel Update to 3.14

CentOS 7.1 Kernel Update to 3.14






  1. 현재 커널 버전 확인


[root@right Desktop]# uname -a
Linux left 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

  1. 업데이트 커널 버전 확인 및 다운로드

    • 다음 사이트에서 최신 커널버전을 확인  한다.

0.PNG
    • 변경할 커널 버전을 다운로드 한다.


    • 설치할 폴더에 압축을 해제 한다.
      (어디다 해도 좋지만 일반적을로 “/usr/src/kernels”밑에 압축을 해제한다.)


[root@right kernels]# pwd
/usr/src/kernels
[root@right kernels]#  xz -d linux-3.14.64.tar.xz
[root@right kernels]# tar -xvf  linux-3.14.64.tar

    • 커널 소스 폴더 생성을 확인.


[root@right kernels]# ls -l
total 76684
drwxrwxr-x 24 root root     4096 Mar  9 22:11 linux-3.14.64


  1. 업데이트 환경 설정& 커널 변수 설정

    • 소스 폴더로 이동 하여 다음의 명령을 실행한다.


[root@right linux-3.14.64]# make mrproper

<< 기존에 설정되어 있던 모든 의존관계 및 환경 설정  값들을 제거 해준다. >>

[root@right linux-3.14.64]# …… 중략……
[root@right linux-3.14.64]# make clean

<<  기존 소스 컴파일 작업으로 생성된 파일들 삭제. >>

[root@right linux-3.14.64]# …… 중략……
[root@right linux-3.14.64]# cp /boot/config-`uname-r` ./.config

<< 현재 사용하고 있는 커널 설정 파일을 3.14 에 사용하기 위하여 소스 폴더에 복사한다. >>
<< 밑 menuconfig 명령으로 실행된 툴에서 로드하여 필요한 부분만 변경한다. >>

[root@right linux-3.14.64]# …… 중략……
[root@right linux-3.14.64]# make menuconfig

<< 커널 설정파일 을 UI를 통해서 조정할 수 있다. >>


<< ※ 커널 설정파일 내용 >>
6.PNG

    • 커널 설정 정보를 로드한후 수정하여 저장한다
      UI 메뉴에서 우측 밑 <Load> 버튼을 클릭하여 소스 폴더 위치에 존재하는 “.config” 파일을 로드 한다.

2.PNG

    • 로드된 커널 설정 파일 에서 다음의 사항을 체크 한다.
      “General setup ---> Enable Deprecated sysfs features to support old userspace tools”을 설정한 후 저장한 후 나온다.

3.PNG
  1. 커널 업데이트


[root@right linux-3.14.64]# make all

<<  커널 설정 파일 .config를 사용하여  커널 소스를 컴파일 한다.>>
<<  한 20분 정도 지나야 끝이 난다. >>

[root@right linux-3.14.64]# …… 중략……
[root@right linux-3.14.64]# make modules_install

<<  컴파일된 모듈들을 설치 >>

[root@right linux-3.14.64]# …… 중략……
[root@right linux-3.14.64]# make install

<< 커널 설치 >>

  1. 부트로더 설정 & 확인

    • centos7 부터는 부트로더로 GRUB2를 사용한다. 또한 자동으로 커널 설치시 부트로더의 설정 파일에 엔트리가 생성된다.

    • /boot/grub2/grub.cfg” 부트로더 파일을 확인 하면 다음 그림과 같이, 부트 로더에 새로 추가한 커널에 해당되는 MenuEntry가 생성 되었음을 확인 할 수 있다.

7.PNG

<< ※  엔트리 순서 >>
기본 엔트리는 마지막으로 부팅한 부트로더가 ,자동으로 기본 엔트리로 포함되며
부팅시에 파일에 기재된 순서대로 표시된다.4.PNG
  1. 리부팅

커널 버전이 3.10 에서 3.14로 변한것을 확인 할 수 있다.

[root@right Desktop]# uname -a
Linux right 3.14.64 #1 SMP Wed Mar 9 21:42:38 PST 2016 x86_64 x86_64 x86_64 GNU/Linux