Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

230224
1178
109352


캐릭터 디바이스(Character Device) Major 번호 자동 등록 Linux Device Driver

리눅스 디바이스 드라이버의 가장 기초는 캐릭터 타입의 디바이스 드라이버죠.
리눅스 커널 교재에서도 많이 소개되어 있는데요.

캐릭터 디바이스 코드를 보다가 한 가지 의문이 생겼어요.
아래 코드는 캐릭터 타입 디바이스의 메이저 번호를 0으로 설정하네요. 어라?
이거 잘못된 코드인가?
static int pacman_probe(struct platform_device *pdev)
{
    pr_debug("%s: %s version %s\n", __func__, DEVICE_NAME, PACMAN_VERSION);

    pacman_ctl.dev_num = register_chrdev(0, DEVICE_NAME, &pacman_fops); //<<--
    if (pacman_ctl.dev_num < 0) {
        pr_err("%s: register_chrdev failed\n", __func__);
        goto register_chrdev_err;
    }


register_chrdev() 함수를 열어보면, 첫 번째 파라미터가 major라고 명시되어 있죠.
static inline int register_chrdev(unsigned int major, const char *name,
  const struct file_operations *fops)
{
return __register_chrdev(major, 0, 256, name, fops);
}


이후에 __register_chrdev() -> __register_chrdev_region() 코드 흐름으로,
__register_chrdev_region 함수가 실행되거든요.
 
잠깐 코드 좀 볼까요? 
 
[1] 번 코드를 보니, 참 메이저 번호가 0일 때 처리하는 조건문이 있어요.
[2]번 코드는 메이저 번호를 인덱스로 바꾸는 구문이네요..
static struct char_device_struct *
__register_chrdev_region(unsigned int major, unsigned int baseminor,
               int minorct, const char *name)
{
    struct char_device_struct *cd, **cp;
    int ret = 0;
    int i;

    cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
    if (cd == NULL)
        return ERR_PTR(-ENOMEM);

    mutex_lock(&chrdevs_lock);

    /* temporary */
    if (major == 0) {  //<<--[1]
        for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
            if (chrdevs[i] == NULL)
                break;
        }

        if (i == 0) {
            ret = -EBUSY;
            goto out;
        }
        major = i;
        ret = major;
    }

    cd->major = major;
    cd->baseminor = baseminor;
    cd->minorct = minorct;
    strlcpy(cd->name, name, sizeof(cd->name));

    i = major_to_index(major); //<<--[2]
static inline int major_to_index(unsigned major)
{
    return major % CHRDEV_MAJOR_HASH_SIZE;  // CHRDEV_MAJOR_HASH_SIZE 255
}

위 코드를 보고 확인할 수 있는 것은, 메이저 번호를 0으로 입력하면 자동으로 메이저 번호를 커널이 등록시켜준다는 거네요.

자, 그럼 캐릭터 타입 디바이스 드라이버는 어느 전역 변수에서 확인할 수 있을까요?
커널에서는 chrdevs 과 cdev_map 변수에서 관리하거든요. 

아래 chrdevs 5번째 멤버를 보면 "/dev/console", "/dev/tty"란 이름의 캐릭터 타입 드라이버가 같은 메이저 번호 5번으로 등록되어 있네요..
(static struct char_device_struct * [255]) chrdevs = (
    [0] = 0x0,
    [1] = 0xDD813500,
    [2] = 0x0,
    [3] = 0x0,
    [4] = 0x0,
    [5] = 0xDD817E00 -> (
      (struct char_device_struct *) next = 0xDD817D00 -> (
        (struct char_device_struct *) next = 0xDDA1FE00,
        (unsigned int) major = 5,
        (unsigned int) baseminor = 1,
        (int) minorct = 1,
        (char [64]) name = "/dev/console",
        (struct cdev *) cdev = 0x0),
      (unsigned int) major = 5,
      (unsigned int) baseminor = 0,
      (int) minorct = 1,
      (char [64]) name = "/dev/tty",
      (struct cdev *) cdev = 0x0),
    [6] = 0x0,
    [7] = 0x0,
    [8] = 0x0,
    [9] = 0x0,
    [10] = 0xDE1F2100,


덧글

댓글 입력 영역