문제

그래서 Linux/Timer.h 파일을 사용하는 커널 모듈을 작성하려고합니다. 모듈 내부에서 작동하게되었고 이제는 사용자 프로그램에서 작동하도록 노력하고 있습니다.

내 커널 모듈은 다음과 같습니다.

//Necessary Includes For Device Drivers.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include <linux/ioctl.h>

#define DEVICE_NAME "mytimer"
#define DEVICE_FILE_NAME "mytimer"
#define MAJOR_NUM 61
#define MINOR_NUM 0

MODULE_LICENSE("Dual BSD/GPL");

static struct timer_list my_timer;

struct file_operations FileOps = 
{
    //No File Operations for this timer.
};

//Function to perform when timer expires.
void TimerExpire(int data)
{
    printk("Timer Data: %d\n", data);
}

//Function to set up timers.
void TimerSetup(void)
{
    setup_timer(&my_timer, TimerExpire, 5678);
    mod_timer(&my_timer, jiffies + msecs_to_jiffies(5000));
}

//Module Init and Exit Functions.
int init_module(void)
{
    int initResult = register_chrdev(MAJOR_NUM, "mytimer", &FileOps);

    if (initResult < 0)
    {
        printk("Cannot obtain major number %d\n", MAJOR_NUM);

        return initResult;
    }

printk("Loading MyTimer Kernel Module...\n");


return 0;
}
void cleanup_module(void)
{
    unregister_chrdev(MAJOR_NUM, "mytimer");
    printk("Unloading MyTimer Kernel Module...\n");
}

보다 구체적으로, 사용자 프로그램이 TimersEtup () 함수를 호출하기를 원합니다. ioctl ()를 사용해야한다는 것을 알고 있지만 module 파일에서 timersetup ()를 ioctl ()을 통해 호출 할 수 있어야한다는 모듈 파일을 지정하는 방법을 잘 모르겠습니다.

또한, 두 번째 질문 : 나는 모듈을 내 모듈에 넣고 mknod를 올바른 주요 숫자로 /dev /mytimer에 넣을 수있었습니다. 그러나 파일 디스크립터를 가져올 수 있도록 ()을 열려고 할 때 -1을 계속 반환했습니다. 나는 권한이 괜찮은지 확인했다 (사실, 나는 그것을 777로 만들었다) ... 여전히 작동하지 않는다 ... 내가 놓친 것이 있습니까?

다음은 다음과 같습니다.

#include <stdio.h>

int main(int argc, char* argv[])
{
    int fd = open("/dev/mytimer", "r");
    printf("fd: %d\n", fd);

    return 0;
}
도움이 되었습니까?

해결책

필요한 예제 코드를 찾을 수 있습니다 drivers/watchdog/softdog.c (Linux 2.6.33에서 작성 당시)는 적절한 파일 작업과 사용자 랜드가 IOCTL ()로 구조를 채우는 방법을 보여줍니다.

실제로 사소한 캐릭터 장치 드라이버를 작성 해야하는 사람을위한 훌륭한 튜토리얼입니다.

SoftDog의 IOCTL 인터페이스를 해부했습니다 내 질문에 대답합니다, 당신에게 도움이 될 수 있습니다.

여기에 그 요점이 있습니다 (철저한 것과는 거리가 멀다) ...

~ 안에 softdog_ioctl() 기능, 버전 및 장치 정보를 광고하는 Struct WatchDog_info의 간단한 초기화가 표시됩니다.

    static const struct watchdog_info ident = {
            .options =              WDIOF_SETTIMEOUT |
                                    WDIOF_KEEPALIVEPING |
                                    WDIOF_MAGICCLOSE,
            .firmware_version =     0,
            .identity =             "Software Watchdog",
    };

그런 다음 사용자가 이러한 기능을 얻으려는 간단한 사례를 살펴 봅니다.

    switch (cmd) {
    case WDIOC_GETSUPPORT:
            return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;

... 물론, 해당 사용자 공간 WatchDog_info를 위의 초기화 값으로 채울 것입니다. copy_to_user ()가 실패하면 -efault가 반환되어 해당 사용자 공간 ioctl () 호출이 의미있는 errno가 설정되어 -1을 반환합니다.

마법 요청은 실제로 Linux/Watchdog.h에 정의되어 커널과 사용자 공간이 공유하도록합니다.

#define WDIOC_GETSUPPORT        _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info)
#define WDIOC_GETSTATUS         _IOR(WATCHDOG_IOCTL_BASE, 1, int)
#define WDIOC_GETBOOTSTATUS     _IOR(WATCHDOG_IOCTL_BASE, 2, int)
#define WDIOC_GETTEMP           _IOR(WATCHDOG_IOCTL_BASE, 3, int)
#define WDIOC_SETOPTIONS        _IOR(WATCHDOG_IOCTL_BASE, 4, int)
#define WDIOC_KEEPALIVE         _IOR(WATCHDOG_IOCTL_BASE, 5, int)
#define WDIOC_SETTIMEOUT        _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
#define WDIOC_GETTIMEOUT        _IOR(WATCHDOG_IOCTL_BASE, 7, int)
#define WDIOC_SETPRETIMEOUT     _IOWR(WATCHDOG_IOCTL_BASE, 8, int)
#define WDIOC_GETPRETIMEOUT     _IOR(WATCHDOG_IOCTL_BASE, 9, int)
#define WDIOC_GETTIMELEFT       _IOR(WATCHDOG_IOCTL_BASE, 10, int)

WDIOC는 분명히 "Watchdog IOCTL"을 의미합니다.

운전자가 무언가를하고 그 결과를 구조에 넣고 사용자 공간에 복사하도록 쉽게 한 걸음 더 나아갈 수 있습니다. 예를 들어, struct watchdog_info도 회원이있는 경우 __u32 result_code. 메모, __u32 커널의 버전 일뿐입니다 uint32_t.

IOCTL ()을 사용하면 사용자는 객체의 주소를 전달합니다. 구조, 정수 등 커널이 동일한 객체에 응답을 작성하고 결과를 제공된 주소로 복사 할 것으로 예상합니다.

두 번째로해야 할 일은 누군가가 열리고, 읽거나, 글을 쓰거나, ioctl ()과 같은 후크를 사용하여 소프트 도그를 공부함으로써 쉽게 볼 수 있습니다.

관심있는 것은 다음과 같습니다.

static const struct file_operations softdog_fops = {
        .owner          = THIS_MODULE,
        .llseek         = no_llseek,
        .write          = softdog_write,
        .unlocked_ioctl = softdog_ioctl,
        .open           = softdog_open,
        .release        = softdog_release,
};

Unlocked_ioctl 핸들러가 보이는 곳은 ... softdog_ioctl ()를 추측했습니다.

나는 당신이 ioctl ()를 다룰 때 실제로 존재하지 않는 복잡성 층을 병치하고 있다고 생각합니다. 정말 간단합니다. 같은 이유로, 대부분의 커널 개발자는 절대적으로 필요한 경우 새로운 IOCTL 인터페이스를 찡그린다. ioctl ()가 당신이하는 마법에 대비하는 유형을 추적하기가 너무 쉽습니다. copy_to_user ()가 종종 실패하는 주된 이유입니다. 디스크 수면.

타이머의 경우, IOCTL ()는 정신의 가장 짧은 경로라는 데 동의합니다.

다른 팁

당신은 누락되었습니다 .open 당신의 기능 포인터 file_operations 프로세스가 장치 파일을 열려고 시도 할 때 호출 할 함수를 지정하는 구조. a를 지정해야합니다 .ioctl IOCTL 기능에 대한 기능 포인터.

읽으십시오 Linux 커널 모듈 프로그래밍 안내서, 특히 4 장 (캐릭터 장치 파일) 및 7 (장치 파일과 대화).

4 장 소개 file_operations 구조는 다음과 같은 다양한 작업을 수행하는 모듈/드라이버에 의해 정의 된 함수에 대한 포인터를 보유합니다. open 또는 ioctl.

7 장 IOCTL을 통해 모듈/드라이브와 통신에 대한 정보를 제공합니다.

Linux 장치 드라이버, 제 3 판 또 다른 좋은 자원입니다.

최소한의 실행 가능한 예

완전히 재현 가능한 QEMU + BuildRoot 환경에서 테스트되었으므로 다른 사람들이 자신의 ioctl 일하고 있는. Github 업스트림 :커널 모듈 | 공유 헤더 | userland.

가장 성가신 부분은 일부 낮은 ID가 납치된다는 것을 이해하는 것이 었습니다. CMD = 2 인 경우 IOCTL이 호출되지 않습니다 , 당신은 사용해야합니다 _IOx 매크로.

커널 모듈 :

#include <asm/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/printk.h> /* printk */

#include "ioctl.h"

MODULE_LICENSE("GPL");

static struct dentry *dir;

static long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long argp)
{
    void __user *arg_user;
    union {
        int i;
        lkmc_ioctl_struct s;
    } arg_kernel;

    arg_user = (void __user *)argp;
    pr_info("cmd = %x\n", cmd);
    switch (cmd) {
        case LKMC_IOCTL_INC:
            if (copy_from_user(&arg_kernel.i, arg_user, sizeof(arg_kernel.i))) {
                return -EFAULT;
            }
            pr_info("0 arg = %d\n", arg_kernel.i);
            arg_kernel.i += 1;
            if (copy_to_user(arg_user, &arg_kernel.i, sizeof(arg_kernel.i))) {
                return -EFAULT;
            }
        break;
        case LKMC_IOCTL_INC_DEC:
            if (copy_from_user(&arg_kernel.s, arg_user, sizeof(arg_kernel.s))) {
                return -EFAULT;
            }
            pr_info("1 arg = %d %d\n", arg_kernel.s.i, arg_kernel.s.j);
            arg_kernel.s.i += 1;
            arg_kernel.s.j -= 1;
            if (copy_to_user(arg_user, &arg_kernel.s, sizeof(arg_kernel.s))) {
                return -EFAULT;
            }
        break;
        default:
            return -EINVAL;
        break;
    }
    return 0;
}

static const struct file_operations fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = unlocked_ioctl
};

static int myinit(void)
{
    dir = debugfs_create_dir("lkmc_ioctl", 0);
    /* ioctl permissions are not automatically restricted by rwx as for read / write,
     * but we could of course implement that ourselves:
     * https://stackoverflow.com/questions/29891803/user-permission-check-on-ioctl-command */
    debugfs_create_file("f", 0, dir, NULL, &fops);
    return 0;
}

static void myexit(void)
{
    debugfs_remove_recursive(dir);
}

module_init(myinit)
module_exit(myexit)

공유 헤더 :

#ifndef IOCTL_H
#define IOCTL_H

#include <linux/ioctl.h>

typedef struct {
    int i;
    int j;
} lkmc_ioctl_struct;
#define LKMC_IOCTL_MAGIC 0x33
#define LKMC_IOCTL_INC     _IOWR(LKMC_IOCTL_MAGIC, 0, int)
#define LKMC_IOCTL_INC_DEC _IOWR(LKMC_IOCTL_MAGIC, 1, lkmc_ioctl_struct)

#endif

사용자 랜드 :

#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "../ioctl.h"

int main(int argc, char **argv)
{
    int fd, arg_int, ret;
    lkmc_ioctl_struct arg_struct;

    if (argc < 2) {
        puts("Usage: ./prog <ioctl-file>");
        return EXIT_FAILURE;
    }
    fd = open(argv[1], O_RDONLY);
    if (fd == -1) {
        perror("open");
        return EXIT_FAILURE;
    }
    /* 0 */
    {
        arg_int = 1;
        ret = ioctl(fd, LKMC_IOCTL_INC, &arg_int);
        if (ret == -1) {
            perror("ioctl");
            return EXIT_FAILURE;
        }
        printf("arg = %d\n", arg_int);
        printf("ret = %d\n", ret);
        printf("errno = %d\n", errno);
    }
    puts("");
    /* 1 */
    {
        arg_struct.i = 1;
        arg_struct.j = 1;
        ret = ioctl(fd, LKMC_IOCTL_INC_DEC, &arg_struct);
        if (ret == -1) {
            perror("ioctl");
            return EXIT_FAILURE;
        }
        printf("arg = %d %d\n", arg_struct.i, arg_struct.j);
        printf("ret = %d\n", ret);
        printf("errno = %d\n", errno);
    }
    close(fd);
    return EXIT_SUCCESS;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top