[カーネルドライバ] カーネルモジュール転送はシンボル共有に参加します

00. 目次

01. 概要

拡張可能な動的モジュールとして、カーネル モジュールは Linux カーネルに柔軟性を提供しますが、プログラムでのデバッグ モードの有効化、詳細な出力モードの設定、公式化など、さまざまなアプリケーション シナリオに応じてさまざまなパラメータをカーネルに渡す必要がある場合があります。特定のモジュール関連のオプションを使用して、パラメーターの形式でモジュールの動作を変更できます。

ここに画像の説明を挿入します

02.モジュールパラメータ

Linux カーネルは、モジュールパラメータの受け渡しを実装するためのマクロを提供します。

module_param 関数 (カーネルソースコード/include/linux/moduleparam.h)

/**
 * module_param - typesafe helper for a module/cmdline parameter
 * @value: the variable to alter, and exposed parameter name.
 * @type: the type of the parameter
 * @perm: visibility in sysfs.
 *
 * @value becomes the module parameter, or (prefixed by KBUILD_MODNAME and a
 * ".") the kernel commandline parameter.  Note that - is changed to _, so
 * the user can use "foo-bar=1" even for variable "foo_bar".
 *
 * @perm is 0 if the the variable is not to appear in sysfs, or 0444
 * for world-readable, 0644 for root-writable, etc.  Note that if it
 * is writable, you may need to use kernel_param_lock() around
 * accesses (esp. charp, which can be kfreed when it changes).
 *
 * The @type is simply pasted to refer to a param_ops_##type and a
 * param_check_##type: for convenience many standard types are provided but
 * you can create your own by defining those variables.
 *
 * Standard types are:
 *  byte, short, ushort, int, uint, long, ulong
 *  charp: a character pointer
 *  bool: a bool, values 0/1, y/n, Y/N.
 *  invbool: the above, only sense-reversed (N = true).
 */
#define module_param(name, type, perm)              \
    module_param_named(name, name, type, perm)


/**
 * module_param_array - a parameter which is an array of some type
 * @name: the name of the array variable
 * @type: the type, as per module_param()
 * @nump: optional pointer filled in with the number written
 * @perm: visibility in sysfs
 *
 * Input and output are as comma-separated values.  Commas inside values
 * don't work properly (eg. an array of charp).
 *
 * ARRAY_SIZE(@name) is used to determine the number of elements in the
 * array, so the definition must be visible.
 */
#define module_param_array(name, type, nump, perm)      \
    module_param_array_named(name, name, type, nump, perm)

上記のコードの module_param 関数は、次の 3 つのパラメーターを渡す必要があります。

  • name:定義した変数名。
  • type:パラメータのタイプ 現在、カーネルでサポートされているパラメータのタイプには、byte、short、ushort、int、uint、long、ulong、charp、bool、および invbool が含まれます。このうち、charp は文字ポインタを表し、bool はブール型で値は 0 または 1 のみ、invbool は逆ブール型で値は 0 または 1 のみですが、true 値は 0 と false を表します。は1を表します。変数の型が char の場合、渡されるパラメータは byte のみ、char * の場合は charp のみです。
  • perm:ファイルのアクセス許可を表します。特定のパラメータ値については、次の表を参照してください。
ユーザー・グループ フラグビット 説明する
現在の使用者 S_IRUSR ユーザーは読み取り権限を持っています
S_IWUSR ユーザーは書き込み権限を持っています
現在のユーザーグループ S_IRGRP 現在のユーザー グループ内の他のユーザーは読み取り権限を持っています
S_IWUSR 現在のユーザー グループ内の他のユーザーは書き込み権限を持っています
他のユーザー S_IROTH 他のユーザーは読み取り権限を持っています
S_IWOTH 他のユーザーは書き込み権限を持っています

上記のファイル権限には実行権限のみが設定されており、このファイルには実行権限が設定されていないことに注意してください。このパラメータに実行許可を示すパラメータ値 S_IXUGO を強制的に割り当てると、最終的に生成されるカーネル モジュールのロード時にエラーが表示されます。

プログラム例

static int itype = 0;
module_param(itype, int, 0);

static bool btype = 0;
module_param(btype, bool, 0644);

static char ctype = 0;
module_param(ctype, byte, 0);

static char  *stype = 0;
module_param(stype, charp, 0644);

static int __init param_init(void)
{
    
    
   printk(KERN_ALERT "param init!\n");
   printk(KERN_ALERT "itype=%d\n",itype);
   printk(KERN_ALERT "btype=%d\n",btype);
   printk(KERN_ALERT "ctype=%d\n",ctype);
   printk(KERN_ALERT "stype=%s\n",stype);
   return 0;
}
  • 行 1 ~ 11: 4 つの共通変数を定義し、module_param マクロを使用してこれらの 4 つのパラメータを宣言します。
  • 13 ~ 21 行目: 上記で宣言した 4 つのパラメータを param_init に出力します。

03. シンボル共有コード

エクスポートされたシンボルに関するカーネル ソース コードは以前に詳細に分析されました。シンボルとは、カーネル モジュールでエクスポートされた関数と変数を指します。モジュールがロードされると、他のモジュールによる呼び出しのためにパブリック カーネル シンボル テーブルに記録されます。このメカニズムにより、階層化されたアイデアを使用して、いくつかの複雑なモジュール設計を解決できるようになります。ドライバーを作成する場合、ドライバーを機能に応じていくつかのカーネル モジュールに分割し、シンボル共有を使用してモジュール間のインターフェイス呼び出しと変数共有を実装できます。

/* For every exported symbol, place a struct in the __ksymtab section */
#define __EXPORT_SYMBOL(sym, sec)               \
    extern typeof(sym) sym;                 \
    __CRC_SYMBOL(sym, sec)                  \
    static const char __kstrtab_##sym[]         \
    __attribute__((section("__ksymtab_strings"), aligned(1))) \
    = VMLINUX_SYMBOL_STR(sym);              \
    extern const struct kernel_symbol __ksymtab_##sym;  \
    __visible const struct kernel_symbol __ksymtab_##sym    \
    __used                          \
    __attribute__((section("___ksymtab" sec "+" #sym), unused)) \
    = {
      
       (unsigned long)&sym, __kstrtab_##sym }

#define EXPORT_SYMBOL(sym)                  \
    __EXPORT_SYMBOL(sym, "")

EXPORT_SYMBOL マクロはシンボルをカーネルにエクスポートするために使用され、エクスポートしたシンボルを他のモジュールでも使用できるようになります。以下は、モジュールを使用してシンボルをエクスポートする方法を紹介するコードです。

プログラム例

static int itype = 0;
module_param(itype, int, 0);

EXPORT_SYMBOL(itype);

int my_add(int a, int b)
{
    
    
   return a + b;
}

EXPORT_SYMBOL(my_add);

int my_sub(int a, int b)
{
    
    
   return a - b;
}

EXPORT_SYMBOL(my_sub);
  • 行 2 ~ 3: パラメーターのタイプが定義され、EXPORT_SYMBOL マクロによってエクスポートされます。
  • 行 7 ~ 12: および my_add、EXPORT_SYMBOL マクロを通じてエクスポート
  • 14 ~ 21 行目: my_sub 関数と EXPORT_SYMBOL マクロを通じてエクスポート

04. プログラム例

追加.h

#ifndef __ADD_H__
#define __ADD_H__

extern int itype;

int my_add(int a, int b);
int my_sub(int a, int b);

#endif

insmod test.ko itype=123 btype=1 ctype=200 stype=abc

追加c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>

#include "add.h"

static int __init cal_init(void)
{
    
    
    printk(KERN_ALERT "cal init!\n");
    printk(KERN_ALERT "itype+1 = %d, itype-1 = %d\n", my_add(itype, 1), my_sub(itype, 1));    

    return 0;
}

static void __exit cal_exit(void)
{
    
    
    printk(KERN_ALERT "cal exit!\n");
}


module_init(cal_init);
module_exit(cal_exit);

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("uplooking");
MODULE_DESCRIPTION("cal module");
MODULE_ALIAS("cal_module");

test.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>

static int itype = 0;
module_param(itype, int, 0);

static bool btype = 0;
module_param(btype, bool, 0700);

static char ctype = 0;
module_param(ctype, byte, 0);

static char  *stype = 0;
module_param(stype, charp, 0644);

static int __init param_init(void)
{
    
    
   printk(KERN_ALERT "param init!\n");
   printk(KERN_ALERT "itype=%d\n",itype);
   printk(KERN_ALERT "btype=%d\n",btype);
   printk(KERN_ALERT "ctype=%d\n",ctype);
   printk(KERN_ALERT "stype=%s\n",stype);
   return 0;
}

static void __exit param_exit(void)
{
    
    
   printk(KERN_ALERT "module exit!\n");
}

EXPORT_SYMBOL(itype);

int my_add(int a, int b)
{
    
    
   return a+b;
}

EXPORT_SYMBOL(my_add);

int my_sub(int a, int b)
{
    
    
   return a-b;
}

EXPORT_SYMBOL(my_sub);

module_init(param_init);
module_exit(param_exit);

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("uplooking");
MODULE_DESCRIPTION("module_param");
MODULE_ALIAS("module_param");

メイクファイル

CROSS_COMPILE=aarch64-linux-gnu-gcc

obj-m := test.o add.o

all:
	$(MAKE) -C $(KERNEL_DIR) M=`pwd` modules

.PHONE:clean
clean:
	$(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean

05. つづく

06. 付録

おすすめ

転載: blog.csdn.net/dengjin20104042056/article/details/132884351