__setupマクロ


__setupマクロはカーネルパラメータによって、動作させるモジュールを定義するマクロです。
[root@localhost lkm]#cat hogehoge.c
#define __attribute_used__   __attribute__ ((__unused__))
#define __initdata           __attribute__ ((__section__ (".data.init")))
#define __init               __attribute__ ((__section__ (".init.text"))

struct obs_kernel_param {
       const char *str;
       int (*setup_func)(char *);
};

#define __setup(str, fn)                                        \
       static char __setup_str_##fn[] __initdata = str;        \
       static struct obs_kernel_param __setup_##fn             \
                __attribute_used__                             \
                __attribute__((__section__(".init.setup")))    \
               = { __setup_str_##fn, fn }

static int init_hoge(void)
{
       return 0;
}

__setup("abcd", init_hoge);
マクロ展開してみる。
[root@localhost lkm]#gcc -E hogehoge.c
struct obs_kernel_param {
       const char *str;
       int (*setup_func)(char *);
};

static int init_hoge(void)
{
       return 0;
}

static char __setup_str_init_hoge[] __attribute__ ((__section__ (".data.init"))) = "abcd";
static struct obs_kernel_param __setup_init_hoge __attribute__((__unused__)) 
    __attribute__((__section__(".init.setup"))) ={ __setup_str_init_hoge, init_hoge };
ちょっと引いてしまいそうですが、要は以下の内容で、__setup_str_init_hoge[]は.data.initに、 __setup_init_hogeは.init.setupセクションに配置する。と言う事です。__setup_init_hogeは、先の例では、abcd"およびinit_hoge()のアドレスが設定されています。なお、__attribute__((__unused__))はこの変数が参照されなくてもワーニングを表示させない。と言うものだそうです。
static char __setup_str_init_hoge[] = "abcd";
static struct obs_kernel_param __setup_init_hoge ={ __setup_str_init_hoge, init_hoge };


start_kernel()からparse_args()でカーネルパラメータを取得し、それを引数としてunknown_bootoption()がコールされます。
asmlinkage void __init start_kernel(void)
{
       char * command_line;
       extern char saved_command_line[];
       extern struct kernel_param __start___param[], __stop___param[];
  :
  :
       printk("Kernel command line: %s\n", saved_command_line);
       parse_args("Booting kernel", command_line, __start___param,
                  __stop___param - __start___param,
                  &unknown_bootoption);
  :
  :
}
unknown_bootoption()のobsolete_checksetup()で、カーネルパラメータにかかる処理を行います。OKなら0が返ってきますが、そうでないとパラーメータエラーとして移行の処理がなされます。
static int __init unknown_bootoption(char *param, char *val)
{
       if (val)
               val[-1] = '=';

       if (obsolete_checksetup(param))
               return 0;

       if (strchr(param, '.') && (!val || strchr(param, '.') < val)) {
               printk(KERN_ERR "Unknown boot option `%s': ignoring\n", param);
               return 0;
       }
  :
  :
       return 0;
}
obsolete_checksetup()で__setup(str, fn)マクロで定義された初期化関数をコールします。__setup_start/__setup_endには.init.setupセクションのアドレスが設定されています(たぶん)。そのポインターをstruct obs_kernel_param pとして、カーネルパラメータとp->strが一致するp->setup_func()をコールしています。
static int __init obsolete_checksetup(char *line)
{
       struct obs_kernel_param *p;
       extern struct obs_kernel_param __setup_start, __setup_end;

       p = &__setup_start;
       do {
               int n = strlen(p->str);
               if (!strncmp(line,p->str,n)) {
                       if (p->setup_func(line+n))
                               return 1;
               }
               p++;
       } while (p < &__setup_end);
       return 0;
}
p->setup_func()の引数は、一致した終端+1以降を引数としています。従って__setup(hogehoge, fn)なら、""を引数で、__setup(hogehoge=, fn)なら、パラメータの設定した=以降の内容を引数としてfnをコールすると言う事です。

最終更新 2013/05/27 23:52:23 - north
(2013/05/27 17:43:42 作成)


検索

アクセス数
3689247
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。