読者です 読者をやめる 読者になる 読者になる

/home/tnishinaga/TechMEMO

日々行ったこと、面白かったことを書き留めます。

Linux Kernelコードを.configの内容に応じてコードを切り替える方法メモ

Linux

一連のツイート

やりたいこと

現在,Linux Kernel 4.6をSTM32F746-discovery(Cortex-M7)上で動作させることを目標に,コードをいじっています.

現時点のMainline Linux Kernel(4.5)は,STM32F746-discoveryには対応していません. しかし,STM32F429I-discovery(Cortex-M4)には対応*1しており,ドライバやDeviceTreeSourceなどが存在しています. そのため,STM32F7への対応は,STM32F4向けのコードをベースに行っています.

それぞれのペリフェラルの差異はレジスタが増減していたりアドレスが違ったりするだけなので,STM32F4のコードをほんの10行程度修正するだけでSTM32F7でも動くようになります. そのため,STM32F4とSTM32F7で別々のドライバを用意するのではなく,以下のように#ifを用いて共通のドライバを一部切り替えるようにして,コードを節約したいです. また,どちらのCPUを使用するかの選択は,カーネルのconfigでいじれるようにしたいです.

#if STM32F7
   // STM32F7向けのレジスタ定義
#else
   // STM32F4向けのレジスタ定義
#endif

やりたいことまとめ

  • #if ディレクティブでマイコンごとにコードを切り替えられるようにしたい
  • 使用するCPUの選択をKernelのconfigで設定できるようにしたい

Kconfig で CPUを選択できるようにする

やりたいことは,以下の2点です.

  • 使用するSoCを.configに設定するのは make ARCH=arm menuconfig から選択して行えるようにしたい
  • STM32F4とSTM32F7は排他的に選択できるようにしたい

まず,menuconfig時に出てくる設定のリストは,各ディレクトリ以下のKconfigファイルに定義されています. 今回のSTM32マイコン向けの設定は arch/arm/Kconfigに書かれているので,これを編集します.

使用するSoCを選択するには,choiceを使えば良いことをnekomatsuさんに教えていただきました. 今回の場合,以下のようにchoiceからendchoiceまでの間にconfigを書くと,排他的に選択ができるようになります.

choice
    prompt "SoC Name"
        depends on ARCH_STM32
    default MACH_STM32F746

config MACH_STM32F429
    bool "STMicrolectronics STM32F429"

config MACH_STM32F746
    bool "STMicrolectronics STM32F746"

endchoice

実際にmenuconfigで開いてみた結果はこんな感じになります.

f:id:tnishinaga:20160411033033p:plain

.configの設定をC言語で使う

さて,次に.configの設定をCやアセンブリのコードで読むにはどうすれば良いのかと調べてみると,詳しく解説されているページがありました.

とあるエンジニアの備忘log: Linux ライクな autoconf.h を簡単に作る

こちらのページに書かれているように,カーネルをmakeした後には include/generated/autoconf.h ができており,このファイルを覗くと先ほど追加した設定が以下の用に定義されていました.

#define CONFIG_MACH_STM32F746 1

つまり,Kconfigに config MACH_STM32F746 と書いたものが選択された場合,MACH_STM32F746の頭にCONFIG_がついた CONFIG_MACH_STM32F746 定数が定義されます. 定数の値は,今回のようにboolの場合は選択時(yes)の場合は1が入ります.

このautoconf.hはすべてのCやアセンブリのビルド時にインクルードされています. なので,STM32F746が選択された場合のみ有効にしたいコードがある場合は,以下のようにして書くことができます.

#if CONFIG_MACH_STM32F746 == 1
 // STM32F746が選択された場合のみ有効にしたいコード
#endif

おわり

以上で.configの設定に応じてコードを切り替えることができるようになりました.

STM32F7でLinux Kernelを動かす件は,今の所シリアル出力が得られるようになりましたが,その他ペリフェラルのサポートはできていません. また,ある方法で起動しないと道中でクラッシュするというよくわからないバグも発生しており,解決できていません. そのあたりはこれから直していく予定です.

おしまい.

*1:動かし方はeLinuxのページにまとまっています