どのように私は私のカーネルモジュールを操作するためのioctl()を使うのですか?

StackOverflow https://stackoverflow.com/questions/2264384

質問

だから私は、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を使用する必要がありますことを知っている)が、私はTimerSetupは、()(ioctlを経由して呼び出し可能である必要があり、私のモジュールファイルで指定するかどうかはわかりません。

また、私の2番目の質問:私は私のモジュールをにinsmodしても、正しいメジャー番号とは/ dev / mytimerにMKNODすることができました。私はそれからファイルディスクリプタを得ることができるように、私は)(それを開こうとしたときにしかし、それは私が間違っていると仮定していた、-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で見つけることができる必要があるサンプルコード()のioctlと構造を埋めるためにユーザランドを許可する方法だけでなく、適切なファイル操作を示し、(Linuxの2.6.33からこれが書かれた時点で)。

これは、実際には些細なキャラクタデバイスドライバを書くために必要がある人のための偉大な、作業のチュートリアルです。

役に立つかもしれ自分の質問を、答えるとき

私がsoftdogのioctlのインタフェースを解剖しましたあなたます。

ここでの要点は、(ただし、遠く網羅から)だ...

softdog_ioctl()では、機能、バージョンやデバイス情報をアドバタイズ構造体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()を呼び出すこと-1有意義errnoが設定されると呼び出しを引き起こす返されます。

注は、魔法の要求が実際にカーネルとユーザー空間は、それらを共有するように、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明らかに意味の "ウォッチドッグのioctl"

あなたは簡単に取ることができ、そのステップはさらに、ドライバが何かをすると構造のその何かの結果を配置し、それがユーザ空間にコピーしました。例えば、構造体watchdog_info場合も、メンバーの__u32 result_codeを持っていました。 __u32がちょうどuint32_tのカーネルのバージョンである、注意します。

IOCTLで()、ユーザは、それがカーネルに同じオブジェクトにその応答を記述し、提供されたアドレスに結果をコピーするカーネルを期待どんな構造、整数、であり、オブジェクトのアドレスを渡します。

あなたがする必要があるとしている2つ目は、お使いのデバイスは、誰かが開いたときに何をすべきかを知っていることを確認していることから読み込み、それへの書き込み、またはあなたが簡単に研究することによって見ることができる、()のioctlのようにフックを使用していますsoftdogます。

興味深いのは、次のとおりです。

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関数ポインタが欠落しています。あなたは同様にあなたのioctl関数について.ioctl関数ポインタを指定する必要があります。

の章具体的には、 Linuxカーネルモジュールプログラミングガイドを通読してください4(キャラクタデバイスファイル)および7(デバイスファイルに話す)。

第4章には、ポインタを保持しているfile_operations構造を導入します例えばopen又はioctl等の各種操作を行うモジュール/ドライバによって定義される関数である。

7章には、/モジュールと通信に関する情報を提供しますioctlを介して駆動ます。

Linuxデバイスドライバ、別の優れたリソースであるの第三版。

の最小実行可能な例

完全に再現可能なQEMU + Buildroot環境でテストするので、他の人が自分のioctlの作業を得るのを助けるかもしれません。上流GitHubの: カーネルモジュールの| 共有ヘッダする | ユーザランドで。

最も厄介な部分はいくつかの低IDがハイジャックされていることを理解しました: ioctlはありますCMD = 2 に、あなたは_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