[커널] App에서 커널 접근하기

정재훈·2022년 5월 9일
0

Kernel

목록 보기
2/8
post-thumbnail

Device Node

디바이스 드라이버 종류

  1. 캐릭터 디바이스(chrdev) : Byte 단위로 값 전달
  2. 블록 디바이스(blkdev) : kb 이상의 블록단위로 값을 전달
  3. 네트워크 디바이스(netdev) : socket 을 열고 ioctl 이라는 System Call 로 장치를 제어

Device Node란?

Device Node는 Device File로 HW 컨트롤을 한다. ./dev에서 장치들을 관리한다.

ls-al ./dev를 하게 되면, 다음 이미지와 같이 확인할 수 있다.

Major Number(주번호) : 디바이스 종류
Minor Number(부번호) : 구분하기 위한 용도

Device 파일 만들기

sudo mknod ./[파일명] c 100 200 : chardev로 주번호 100 보조번호 200인 device file 생성

App에서 커널 접근하기

커널 내부에서 디바이스 파일과 커널 모듈을 연결하여, app 단에서 디바이스 파일을 열어서 커널 모듈을 제어한다.

app에서 Device 파일에 접근하기

nobran.c 기본형태

#include <linux/module.h>

MODULE_LICENSE("GPL");

static int nobrand_init(void) {
    printk( KERN_INFO "OK HELLO NOBRAND!!\n");
    return 0;
}

static void nobrand_exit(void) {
    printk( KERN_INFO "BYE BYE\n\n");
}

module_init(nobrand_init);
module_exit(nobrand_exit);

Device File
./dev는 장치 파일을 제어해주는 디렉토리, 디바이스 파일은 ./dev에 저장되어 있어야 한다.
sudo mknod /dev/nobrand c 100 0
sudo chmod 666 /dev/nobrand

app.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    printf("OPEN FILE!!\n");
    int fd = open("/dev/nobrand", O_RDONLY); // 디바이스 파일에 접근하기
    if (fd == -1)
    {
        printf("FILE OPEN ERROR\n");
        return 0;
    }


    printf("CLOSE FILE!!\n");
    close(fd);

    return 0;
}

커널 모듈형태의 Device Driver 제작

nobrand.c 완성본

#include <linux/module.h>
#include <linux/fs.h>

#define NOD_NAME "nobrand"
#define NOD_MAJOR 100  // Device File의 Major Number

MODULE_LICENSE("GPL");

static int nobrand_open(struct inode *inode, struct file *filp) {
    printk( KERN_INFO "OPEN!!!\n");
    return 0;
}

static int nobrand_release(struct inode *inode, struct file *filp) {
    printk( KERN_INFO "CLOSE!!!\n");
    return 0;
}

static struct file_operations fops = {
    .open = nobrand_open,  // app.c에서 open 명령어 실행시 실행
    .release = nobrand_release // app.c에서 close 명령어 실행시 실행
};

static int nobrand_init(void) {  // insmod 명령어 입력시 실행
    printk( KERN_INFO "OK HELLO NOBRAND!!\n");  // KERN_INFO : log에 print하기 위해
    if (register_chrdev(NOD_MAJOR, NOD_NAME, &fops) < 0) { // device file에 접근 실패시 실행
        printk( KERN_INFO "ERROR!!! register error\n");
    }

    return 0;
}

static void nobrand_exit(void) { // rmmod 명령어 입력시 실행
    unregister_chrdev(NOD_MAJOR, NOD_NAME);
    printk( KERN_INFO "BYE BYE\n\n");
}



module_init(nobrand_init);
module_exit(nobrand_exit);

makefile

KERNEL_SRC=/lib/modules/$(shell uname -r)/build
obj-m := nobrand.o

go:
    make -C $(KERNEL_SRC) M=$(PWD) modules
clean:
    make -C $(KERNEL_SRC) M=$(PWD) clean

KERNEL_SRC 경로에 Makefile이 존재한다. 해당 Makefile에 선언해준 obj-m이 있다.
PWD(현재 경로)의 모든 파일을 커널에 접근하여 make를 통해 나온 결과물을 다시 가져오게된다.

실행

make를 통해 커널 모듈 빌드
sudo insmod ./nobrand.ko를 통해 커널에 집어넣기
gcc ./app.c -o ./app을 통해 app 파일 빌드
./app을 통해 app에서 커널 모듈에 접근
sudo rmmod nobrand를 통해 커널에서 빼기

참고 : ko 파일은 test용으로 app단에 존재하는거지, 원래는 커널에 있어야한다.

재부팅 시 실행 순서

재부팅시 필요한 파일들을 만들어주는데, 상단에서 만든 nobrand 파일은 필수가 아니므로 다시 만들어줘야한다.
$ make clean
$ rm app
$ sudo mknod /dev/nobrand c 100 0
$ sudo chmod 666 /dev/nobrand
$ make
$ gcc app.c -o app
터미널 새로 키고 $ dmesg -w
$ sudo insmod nobrand.ko
$ ./app
$ sudo rmmod nobrand
$ make clean
$ rm app

좀더 간편화

Makefile 수정

app gcc를 추가

KERNEL_SRC=/usr/src/linux
TARGET := app
obj-m := nobrand.o

all: driver app

driver:
        make -C $(KERNEL_SRC) M=$(PWD) modules

app:
     $(CC) -o $@ $@.c

clean:
     make -C $(KERNEL_SRC) M=$(PWD) clean
     rm -f *.o $(TARGET)

alias.sh 파일 만들기

source ./alias.sh로 실행가능
매크로 함수로, sd로 커널 진입 , sc로 커널 빠져나오기

alias sc='sudo insmod ./nobrand.ko'
alias sd='sudo rmmod nobrand'
profile
여러 방향으로 접근하는 개발자

0개의 댓글