#author("2017-09-13T00:53:37+09:00","default:afuruta","afuruta") #author("2017-09-13T13:00:25+09:00","default:afuruta","afuruta") * kernel に組み込む [#z58435ff] i8253 PIT をアクセスするドライバのうち、i8253 の channel 1 を platform device として登録する [[i8253_ref_setup.c]] を kernel に組み込み、その結果を確かめることをします。 * kernel source にパッチを当てる [#j8497ca2] 添付ファイル &ref(i8253_ref_setup.diff); は kernel source に当てるパッチです。内容は [[Kconfig と Makefile 修正の詳細>#patch_in_detail]]、[[i8253_ref 全体のデータ構造>i8253 PIT をアクセスするデバイスドライバ#wc5356f6]]、[[i8253_ref_setup.c: kernel に platform device を登録する>i8253 PIT をアクセスするデバイスドライバ#gb51e87e]] を参照して下さい。このファイルをダウンロードして、kernel source の root directory (linux-stable) にカレント・ディレクトリを移し、次の様にして kernel にパッチを当てます。色々と修正を試みた後、ソースを元に戻すことも考慮し、branch i8253_ref_setup を作る操作も込みで示しています。branch 名は好きに付けても良いです。 #pre(soft){{ &span(ConsoleOut){linux-stable $ };&span(ConsoleIn){git checkout -b i8253_ref_setup}; &span(ConsoleOut){linux-stable $ };&span(ConsoleIn){git patch };&span(ConsoleIn,Alias){down_loaded_directory};&span(ConsoleIn){/i8253_ref_setup.diff}; }} 続けて新しく追加した configuration 項目 (Kconfig の内容) を .config に反映するため &span(ConsoleIn){make menuconfig}; を実行します。 #pre(soft){{ &span(ConsoleOut){linux-stable $ };&span(ConsoleIn){make menuconfig}; }} menuconfig の中で &span(ConsoleOut){Processor type and features}; を選択します。 #pre(soft){{ &span(ConsoleOut){ .config - Linux/x86 4.1.27 Kernel Configuration}; &span(ConsoleOut){ ──────────────────────────────────────────────────────────────────────────────}; &span(ConsoleOut){ ┌───────────────── Linux/x86 4.1.27 Kernel Configuration ─────────────────┐}; &span(ConsoleOut){ │ Arrow keys navigate the menu. <Enter> selects submenus ---> (or empty │}; &span(ConsoleOut){ │ submenus ----). Highlighted letters are hotkeys. Pressing <Y> │}; &span(ConsoleOut){ │ includes, <N> excludes, <M> modularizes features. Press <Esc><Esc> to │}; &span(ConsoleOut){ │ exit, <?> for Help, </> for Search. Legend: [*] built-in [ ] │}; &span(ConsoleOut){ │ ┌─────────────────────────────────────────────────────────────────────┐ │}; &span(ConsoleOut){ │ │ [*] 64-bit kernel │ │}; &span(ConsoleOut){ │ │ General setup ---> │ │}; &span(ConsoleOut){ │ │ [*] Enable loadable module support ---> │ │}; &span(ConsoleOut){ │ │ [*] Enable the block layer ---> │ │}; &span(ConsoleOut){ │ │ };&span(ConsoleOut,Focus){Processor type and features --->};&span(ConsoleOut){ │ │}; &span(ConsoleOut){ │ │ Power management and ACPI options ---> │ │}; &span(ConsoleOut){ │ │ Bus options (PCI etc.) ---> │ │}; &span(ConsoleOut){ │ │ Executable file formats / Emulations ---> │ │}; &span(ConsoleOut){ │ │ [*] Networking support ---> │ │}; &span(ConsoleOut){ │ │ Device Drivers ---> │ │}; &span(ConsoleOut){ │ │ Firmware Drivers ---> │ │}; &span(ConsoleOut){ │ │ File systems ---> │ │}; &span(ConsoleOut){ │ │ Kernel hacking ---> │ │}; &span(ConsoleOut){ │ │ Security options ---> │ │}; &span(ConsoleOut){ │ │ -*- Cryptographic API ---> │ │}; &span(ConsoleOut){ │ │ -*- Virtualization ---> │ │}; &span(ConsoleOut){ │ └────┴(+)─────────────────────────────────────────────────────────────┘ │}; &span(ConsoleOut){ ├─────────────────────────────────────────────────────────────────────────┤}; &span(ConsoleOut){ │ <Select> < Exit > < Help > < Save > < Load > │}; &span(ConsoleOut){ └─────────────────────────────────────────────────────────────────────────┘}; }} 項目 &span(ConsoleOut){I8253 PIT Refresh timer driver}; に * を付けた状態にします。menuconfig を .config に変更を反映する選択をして終了します。 #pre(soft){{ &span(ConsoleOut){ .config - Linux/x86 4.1.27 Kernel Configuration}; &span(ConsoleOut){ };&span(ConsoleOut,Focus){> Processor type and features};;&span(ConsoleOut){ ────────────────────────────────────────────────}; &span(ConsoleOut){ ┌────────────────────── Processor type and features ──────────────────────┐}; &span(ConsoleOut){ │ Arrow keys navigate the menu. <Enter> selects submenus ---> (or empty │}; &span(ConsoleOut){ │ submenus ----). Highlighted letters are hotkeys. Pressing <Y> │}; &span(ConsoleOut){ │ includes, <N> excludes, <M> modularizes features. Press <Esc><Esc> to │}; &span(ConsoleOut){ │ exit, <?> for Help, </> for Search. Legend: [*] built-in [ ] │}; &span(ConsoleOut){ │ ┌────^(-)─────────────────────────────────────────────────────────────┐ │}; &span(ConsoleOut){ │ │ [*] Enable IOSF sideband access through debugfs │ │}; &span(ConsoleOut){ │ │ [*] Single-depth WCHAN output │ │}; &span(ConsoleOut){ │ │ [*] Linux guest support ---> │ │}; &span(ConsoleOut){ │ │ Processor family (Generic-x86-64) ---> │ │}; &span(ConsoleOut){ │ │ [*] Supported processor vendors ---> │ │}; &span(ConsoleOut){ │ │ };&span(ConsoleOut,Focus){[*] I8253 PIT Refresh timer driver (NEW)};&span(ConsoleOut){ │ │}; &span(ConsoleOut){ │ │ [*] Enable DMI scanning │ │}; &span(ConsoleOut){ │ │ [*] Old AMD GART IOMMU support │ │}; &span(ConsoleOut){ │ │ [*] IBM Calgary IOMMU support │ │}; &span(ConsoleOut){ │ │ [*] Should Calgary be enabled by default? │ │}; &span(ConsoleOut){ │ │ [ ] Enable Maximum number of SMP Processors and NUMA Nodes │ │}; &span(ConsoleOut){ │ │ (256) Maximum number of CPUs │ │}; &span(ConsoleOut){ │ │ [*] SMT (Hyperthreading) scheduler support │ │}; &span(ConsoleOut){ │ │ [*] Multi-core scheduler support │ │}; &span(ConsoleOut){ │ │ Preemption Model (Voluntary Kernel Preemption (Desktop)) ---│ │}; &span(ConsoleOut){ │ │ [*] Reroute for broken boot IRQs │ │}; &span(ConsoleOut){ │ └────┴(+)─────────────────────────────────────────────────────────────┘ │}; &span(ConsoleOut){ ├─────────────────────────────────────────────────────────────────────────┤}; &span(ConsoleOut){ │ <Select> < Exit > < Help > < Save > < Load > │}; &span(ConsoleOut){ └─────────────────────────────────────────────────────────────────────────┘}; }} #textbox(thought,I8253 PIT Refresh timer driver の階層がおかしくないか?){{ "&span(ConsoleOut){I8253 PIT Refresh timer driver};" のメニュー階層に違和感があるのは確かです。メニュー階層を menu-endmenu で作るか、config 項目を "&span(ConsoleOut){Device Drivers};" の囲みの中に作るかすれば違和感は減ると思います。ソースファイルの位置と Kconfig ファイルの位置関係もなるべく近くにしつつ menuconfig も違和感なく構成するのに難しい題材なのかもしれません。Kconfig についての詳細は &ogfileone(/Documentation/kbuild/kconfig-language.txt); を見て下さい。 }} * 構築 と install [#z5732a47] 構築と install は [[チュートリアルページの構築編>Tutorial#u0ace359]] を参考にして下さい。このページのパッチを当てる前に # make modules_install; make install が済んでいて、構築済みの kernel 起動を確認できているならば grub の修正と更新手順を省略して下さい。 * 動作確認 [#a61a3c7a] kernel に組み込んだ i8253_ref_setup.c で platform device を組み込みました。組み込んだ kernel を起動すると kernel (/drivers/base) で管理している device の情報に変化が起きています。変化を見ていきます。 ** /proc/ioports [#z1a6ac00] [[i8253_ref_setup.c]] の中で &ogdefs(resource,resource,ioports.h); 構造体の配列で定義した I/O ポートが /proc/ioports に反映されます。ポート名は /include/linux 以下に配置した [[i8253_ref.h]] の中で定義されています。 #pre(soft,overflow:auto, max-width:960px){{ &span(ConsoleOut){~ $ };&span(ConsoleIn){cd /proc}; &span(ConsoleOut){/proc $ };&span(ConsoleIn){cat ioports}; &span(ConsoleOut){0000-0cf7 : PCI Bus 0000:00}; &span(ConsoleOut){ 0000-001f : dma1}; &span(ConsoleOut){ 0020-0021 : pic1}; &span(ConsoleOut){ 0040-0043 : timer0}; &span(ConsoleOut){ };&span(ConsoleOut,Focus){0041-0041 : refresh_counter}; &span(ConsoleOut){ };&span(ConsoleOut,Focus){0043-0043 : control_word}; &span(ConsoleOut){ 0050-0053 : timer1}; &span(ConsoleOut){ 0060-0060 : keyboard}; &span(ConsoleOut){ 0061-0061 : PNP0800:00}; &span(ConsoleOut){ 0064-0064 : keyboard}; &span(ConsoleOut){ 0070-0071 : rtc0}; &span(ConsoleOut){ 0080-008f : dma page reg}; &span(ConsoleOut){ 00a0-00a1 : pic2}; &span(ConsoleOut){ 00c0-00df : dma2}; &span(ConsoleOut){ 00f0-00ff : PNP0C04:00}; &span(ConsoleOut){ 00f0-00ff : fpu}; &span(ConsoleOut){ 0170-0177 : 0000:00:06.0}; &span(ConsoleOut){ 0170-0177 : pata_amd}; -- snip -- }} ** /sys/devices/platform/i8253_ref.0.auto [#q18ecde1] i8253_ref_setup.c の中で &ogdefs(platform_device_register()); で登録したデバイスが i8253_ref.0.auto ディレクトリとして現れます。&ogdefs(platform_device); 構造体のメンバを id = &ogdefs(PLATFORM_DEVID_AUTO);, id_auto = true としたので、デバイス名の後ろに ".0.auto" が自動的に付加されています。 #pre(soft,overflow:auto, max-width:960px){{ &span(ConsoleOut){/proc $ };&span(ConsoleIn){cd /sys/devices/platform}; &span(ConsoleOut){/sys/devices/platform $ };&span(ConsoleIn){ls -la}; &span(ConsoleOut){total 0}; &span(ConsoleOut){drwxr-xr-x 13 root root 0 9 9 10:46 .}; &span(ConsoleOut){drwxr-xr-x 12 root root 0 9 9 10:46 ..}; &span(ConsoleOut){drwxr-xr-x 4 root root 0 9 9 10:46 Fixed MDIO bus.0}; &span(ConsoleOut){drwxr-xr-x 3 root root 0 9 9 10:46 PNP0C0B:00}; &span(ConsoleOut){drwxr-xr-x 3 root root 0 9 9 10:46 PNP0C0C:00}; &span(ConsoleOut){drwxr-xr-x 3 root root 0 9 9 10:46 alarmtimer}; &span(ConsoleOut){drwxr-xr-x 4 root root 0 9 9 10:46 i8042}; &span(ConsoleOut){drwxr-xr-x 3 root root 0 9 9 10:46 };&span(ConsoleOut,Focus){i8253_ref.0.auto}; &span(ConsoleOut){drwxr-xr-x 3 root root 0 9 9 10:46 pcspkr}; &span(ConsoleOut){drwxr-xr-x 3 root root 0 9 9 10:46 platform-framebuffer.0}; &span(ConsoleOut){drwxr-xr-x 2 root root 0 9 10 16:11 power}; &span(ConsoleOut){drwxr-xr-x 4 root root 0 9 9 10:46 reg-dummy}; &span(ConsoleOut){drwxr-xr-x 4 root root 0 9 9 10:46 serial8250}; &span(ConsoleOut){-rw-r--r-- 1 root root 4096 9 9 10:46 uevent}; &span(ConsoleOut){/sys/devices/platform $ };&span(ConsoleIn){cd i8253_ref.0.auto}; &span(ConsoleOut){/sys/devices/platform/i8253_ref.0.auto $ };&span(ConsoleIn){ls -la}; &span(ConsoleOut){ 0}; &span(ConsoleOut){drwxr-xr-x 3 root root 0 9 10 16:11 .}; &span(ConsoleOut){drwxr-xr-x 13 root root 0 9 10 16:11 ..}; &span(ConsoleOut){-rw-r--r-- 1 root root 4096 9 10 16:11 driver_override}; &span(ConsoleOut){-r--r--r-- 1 root root 4096 9 10 16:11 modalias}; &span(ConsoleOut){drwxr-xr-x 2 root root 0 9 10 16:11 power}; &span(ConsoleOut){lrwxrwxrwx 1 root root 0 9 9 10:46 subsystem -> ../../../bus/platform}; &span(ConsoleOut){-rw-r--r-- 1 root root 4096 9 9 10:46 uevent}; }} ドライバ [[i8253_ref.c]] を組み込むと /sys/devices/platform/i8253_ref.0.auto ディレクトリの中に counter, rate ノードが &ogdefs(sysfs_create_group()); の呼び出しによって作られます。次は [[i8253_ref.c]] から構築した i8253_ref.ko を組み込んだ後の様子です。 #pre(soft,overflow:auto, max-width:960px){{ &span(ConsoleOut){/sys/devices/platform/i8253_ref.0.auto # };&span(ConsoleIn){ls -la}; &span(ConsoleOut){total 0}; &span(ConsoleOut){drwxr-xr-x 3 root root 0 9 10 16:12 .}; &span(ConsoleOut){drwxr-xr-x 13 root root 0 9 10 16:11 ..}; &span(ConsoleOut){-r--r--r-- 1 root root 4096 9 10 16:13 };&span(ConsoleOut,Focus){counter}; &span(ConsoleOut){lrwxrwxrwx 1 root root 0 9 10 16:13 driver -> ../../../bus/platform/drivers/i8253_ref}; &span(ConsoleOut){-rw-r--r-- 1 root root 4096 9 10 16:11 driver_override}; &span(ConsoleOut){-rw-r--r-- 1 root root 4096 9 10 16:13 dump_stack}; &span(ConsoleOut){-r--r--r-- 1 root root 4096 9 10 16:11 modalias}; &span(ConsoleOut){drwxr-xr-x 2 root root 0 9 10 16:11 power}; &span(ConsoleOut){-rw-r--r-- 1 root root 4096 9 10 16:13 };&span(ConsoleOut,Focus){rate}; &span(ConsoleOut){lrwxrwxrwx 1 root root 0 9 10 16:11 subsystem -> ../../../bus/platform}; &span(ConsoleOut){-rw-r--r-- 1 root root 4096 9 10 16:11 uevent}; &span(ConsoleOut){/sys/devices/platform/i8253_ref.0.auto # };&span(ConsoleIn){echo 32768 > rate}; &span(ConsoleOut){/sys/devices/platform/i8253_ref.0.auto # };&span(ConsoleIn){cat rate}; &span(ConsoleOut){32768}; &span(ConsoleOut){/sys/devices/platform/i8253_ref.0.auto # };&span(ConsoleIn){cat counter}; &span(ConsoleOut){16752}; &span(ConsoleOut){/sys/devices/platform/i8253_ref.0.auto # };&span(ConsoleIn){cat counter}; &span(ConsoleOut){8201}; }} * kernel に静的にソースを結合する方法 [#patch_in_detail] パッチ &ref(i8253_ref_setup.diff); の中で、新しくソースファイルを用意する、あるいは既存のソースに修正を加えた場合に必要な作業の参考になる部分を見ていきます。 platform device として I8253 PIT を kernel に登録する処理 [[i8253_ref_setup.c]] を kernel に静的に結合する(スタティック・リンク)する方法を見ていきます。新しく作ったソース・ファイルを kernel にスタティック・リンクするのに最低限必要なことは次の通りです。 - ソースを配置したディレクトリまたはその上流に辿る経路で近い場所にある Makefile を修正しコンパイル・リンクする対象に加える。 - ソースファイルから上流に辿る経路で近い場所にある Kconfig ファイルに新しく作ったソースをコンパイル・リンク対象にするのかどうか &span(ConsoleIn){make menuconfig}; で選択できる様にする。 - ソースを配置したディレクトリまたは root に辿る経路で近い場所にある Makefile を修正しコンパイル・リンクする対象に加える。 - ソースファイルを配置したディレクトリまたは root に辿る経路で近い場所にある Kconfig ファイルに新しく作ったソースをコンパイル・リンク対象にするのかどうか &span(ConsoleIn){make menuconfig}; で選択できる様にする。 &span(ConsoleIn){make menuconfig}; で新しく加えたソース・ファイルをコンパイル対象にするかどうか選択できる様にしておくと、チーム開発をしている状況での問題の切り分け、開発環境の足並みが揃っていない状況で柔軟に対応することができます。 ** Makefile [#q2da03c6] /arch/x86/kernel/Makefile の変更箇所は次の通りです。 #code(diff,i8253_ref-kernel-Makefile/Makefile.diff); &span(Code){obj-$(CONFIG_I8253_REFRESH) += i8253_ref_setup.o}; は CONFIG_I8253_REFRESH を展開した結果によって &span(Code){obj- += i8253_ref_setup.o}; または &span(Code){obj-y += i8253_ref_setup.o}; と解釈されます。ここでは出てきませんが CONFIG_I8253_REFRESH が tristate (モジュール) の場合は &span(Code){obj-m += i8253_ref_setup.o}; となる場合が有ります。&span(Code){obj-y += i8253_ref_setup.o}; となった場合、kernel に静的に結合します。 |obj-* += file.o |構築結果|h |obj- += file.o |file.c はコンパイルされない| |obj-y += file.o |file.c は kernel に静的に結合(スタティックリンクされる)| |obj-m += file.o |file.c はモジュールとして構築され file.ko が作られる (このページでは扱いません)| ** Kconfig [#m2a019a5] arch/x86/Kconfig の変更箇所は次の通りです。この Kconfig の位置は例外的に Makefile と ソースファイル i8253_ref_setup.c が有るディレクトリと違っています。この修正で &span(ConsoleIn){make menuconfig}; で i8253_ref_setup.c を kernel に組み込むかどうか前節の Makefile の修正と併せ選択することができる様になります。詳細な書き方は &ogfileone(/Documentation/kbuild/kconfig-language.txt); を参照して下さい。 #code(diff,i8253_ref-kernel-kconfig/Kconfig.diff); config I8253_REFRESH で選択項目を宣言します。ここでは接頭辞 CONFIG_ を付けずに書くことに注意して下さい。bool は y か n (定義しない)の選択だと言う意味です。default は n (定義しない)、 depends on X86 は X86(CONFIG_X86) が定義されれば選択項目に現れることを意味します。help は &span(ConsoleIn){make menuconfig}; で help を要求したときに表示されるテキストです。他の項目で ---help--- と書かれているところもあります。どちらも同様に解釈されます。help の部分はインデントに意味があります。他の部分のインデントも慣例的に合わせて書くことをお勧めします。 #textbox(note,追加した config 項目は make menuconfig のどこに現れるの?){{ &span(ConsoleIn){make menuconfig}; を実行して追加した項目がどこに行ったか分からなくなるかもしれません。丁寧に Kconfig の menu-endmenu のネスティングを追って十分に理解する方法と、手っ取り早く知るために &span(ConsoleIn){make menuconfig}; で対話的設定を開始したところで &span(ConsoleIn){/}; を押してマクロ名を検索する方法があります。このページの例では &span(ConsoleIn){I8253_REFRESH}; を探す文字列とします。&span(ConsoleOut){Location:}; 以下に場所のパスが示されます。丁寧に Kconfig の階層構造を探すより早いです。 }} #textbox(note,他の architecture や platform の場合、どこにソース・コードを追加して、どこの Makefile や Kconfig の修正をしたら良いの?){{ 開発ターゲットの基板に実装されたテバイスを追加するために /arch/&span(Alias){processor}; 以下に配置されたファイルを修正したり、追加するやり方に迷うかもしれません。ディレクトリ構成はプロセッサ(CPU)毎に大きく違います。見回してみて、しっくりする修正方法を考えてください。似たようなデバイスを見つけて並べるように修正するのが良いでしょう。他のプロセッサに比べて派生品種が多い ARM 系では /arch/arm/plat-&span(Alias){platform}; に SoC 毎に派生するコード、/arch/arm/mach-&span(Alias){machine}; に基板品種毎に派生する(付加した周辺回路によって派生する)コードが含まれることが多いです(SoC 毎に派生するコードもあります)。 }}