チュートリアル環境を構築する

好きにいじれる Linux kernel を用意する

仮想環境を使い Linux kernel 内で動作するプログラムを作っていきます。ユーザー・ランドで動作するプログラムとの違い。Linux kernel の様子を探っていきます。ここでは linux で動作する VirtualBox を使用します。Windows で動作する VirtualBox も利用できます。Windows で動作する VirtualBox では不便な場面は有るかと思いますが、なるべく困らないようにしていきたいと思います。

仮想マシンを用意する

仮想マシンを作成する

VirtualBox に次のような設定の仮想マシンを用意してください。他の仮想環境を使う場合は、よく似た環境にしてください。

構成要素設定説明
仮想マシンOS (Type)linuxこの OS のデバイス・ドライバ開発の話ですので。
仮想マシンディストリビューション (Version)Ubuntu ホストと同じ CPU 語長Ubuntuを使用します。Release を指定できる場合は 14.04 を指定してください。仮想マシンの CPU 語長はホスト環境と同じにする事を推奨します。ホストマシンと合わせる目的は、コンパイル速度が遅い場合、ホストマシンで補助しやすくするためです。
仮想マシンメモリ容量 (Base Memory)1024Mibyte 以上遅いですが、セルフコンパイルを実施するためです。gitk を活用するつもりであれば 4096Mibyte 以上にしてください。
プロセッサ数(Processor(s))2 個以上2個を割り当てると可能な実験をする予定です。
リモート・ディスプレイ(Remote Display)Disableリモートディスプレイ機能は使用する予定が無いので disable で良いです。
光学ドライブ (optical drive)1 台Ubuntu インストーラー ISO イメージをマウントします。
ハード・ディスク (hard disk)1 台, 200G byteUbuntu、Linux kernel ソース、それをコンパイルしたオブジェクトを格納します。容量の 100% まで使用する予定はないので動的確保(Dynamically Allocated)で構成してください。
ネットワーク・アダプタ接続 (Attached to)bridged adapterブリッジ接続をおすすめします。ssh で入ることで状況を立て直せる場合もあります。ネットワークにコンピュータを追加できない場合は NAT, Internal Network, Host Only network を使い分けるか複数用意してください。
シリアル・ポート番号 (Port Number)COM1もしかしたら使うかもしれません。
シリアル・ポート・モード (Port Mode)Disconnectedもしかしたら使うかもしれません。

次は VirtualBox の仮想マシン設定一覧の画像です。赤線を引いたところは設定を必要とする項目です。

vbox-055-caped.png

仮想マシンに Ubuntu をインストールする

単純なパーティション構成で Ubuntu をインストールします。Installation Type にて Erase disk and install Ubuntu を選びます。

vbox-090-resize.png

次の表のようにパーティションが分割されます。

パーティションファイル・システムマウント・ポイント備考
/dev/sda1ext4/殆どこのパーティションに容量が割れ当てられます。
/dev/sda5swapおおよそメモリ容量と同じ量が割り当てられます。

次はパーティション分割を終えた後のスクリーン・ショットです。

仮想マシンの画面がせまい

インストール後、仮想マシンの画面がせまく感じる場合は filexorg.conf ファイルを root 権限で /etc/X11 ディレクトリにコピーしてください。logout/login 後に画面サイズは 1280x1024 になります。解像度を下げたい場合は、xorg.conf の Modes 行の解像度名(たとえば "1280x1024")を削除してください。

パッケージ追加

私の好みも含め、パッケージを追加しデバイス・ドライバ開発に備えます。apt-get install を目的別に書いたので、お手数をおかけします。

  • ssh server をインストールする
    $ sudo apt-get install ssh
    $ sudo service ssh start
    $ ifconfig  # IP アドレスを調べてリモートより操作する手掛かりを収集
    
  • system V init ツールをインストールする
    $ sudo apt-get install sysv-rc-conf
    
  • ssh server を常に起動しておく
    $ sudo sysv-rc-conf --level 2345 ssh on
    
  • git ツールをインストールする
    $ sudo apt-get install git gitk git-gui
    $ sudo git config --global user.name "Your Name"  # Your Name の部分は英語で自分の名前にします。
    $ sudo git config --global user.email "your.email@example.com"  # your.email... の部分はメールアドレスら置き換えます。
    
  • kernel source を make するのに必要なツールをインストールする
    curses ライブラリを使い、テキスト文字によって視覚的に把握しやすい画面を通してコンパイル条件を設定するために使います。
    $ sudo apt-get install libncurses-dev xmlto
    

    ノート

    git gui コマンドを使って GUI の git ツールを起動し、commit を行った人の名前、メールアドレスに加えスペルチェック機能も設定すると便利です。

  • grub2 boot loader を更新するのに必要なツールをインストールする。
    $ sudo apt-get install grub2
    
  • (好みで) NFS server をインストールする
    NFS server 機能を使うことでコンパイルをホスト・マシンなど早いコンピュータで行うことができます。
    $ sudo apt-get install nfs-kernel-server
    $ sudo service nfs-kernel-server on
    $ sudo sysv-rc-conf --level 2345 nfs-kernel-server on
    

    ノート

    設定ファイル /etc/exportfs を編集していないので NFS で共有するディレクトリはありません。 /etc/exportfs を編集した後、sudo service nfs-kernel-server reload で設定が有効になります。

  • (好みで) samba server をインストールする
    $ sudo apt-get install samba winbind libnss-winbind
    $ sudo sysv-rc-conf --level 2345 nmb on
    $ sudo sysv-rc-conf --level 2345 smb on
    $ sudo sysv-rc-conf --level 2345 winbind on
    $ sudo nano /etc/samba/smb.conf  # samba 設定内容を好みに合わせて編集
    $ sudo nano /etc/nsswitch.conf  # hosts: 行に有る dns の前に wins を追加
    $ sudo service nmb start
    $ sudo service smb start
    $ sudo service winbind start
    

ソースを取ってくる

Linux kernel のソースコードを取得します。ローカルの git リポジトリを置く場所を git_base_directory とします。ソース・コードを clone すると git_base_directory/linux-stable 以下に取得したファイルが配置されます。次に示す手順は、git_base_directory を作成することを前提としています。ホームディレクトリ直下に配置する場合は、git_base_directory を作成するコマンドは省略してもよいです。

$ mkdir -p git_base_directory
$ cd git_base_directory
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git

ノート

git clone コマンドは完了するのに 2 時間 ~ 半日程度かかる場合があります。

コンパイルができる様に準備する

Ubuntu 14.04 に使っている Linux kernel よりは新しく、long term で更新されている kernel を選びます。これを書いている時点で 4.1.27 を選択しました。ローカルの git repository に 4.1.27-local branch を作成し作業を進めます。次のようにします。これより後、特に断りがなければ、先の節でソースコードが配置されたディレクトリ git_base_directory/linux-stable を単に linux-stable と表現します。

$ cd linux-stable
$ git checkout v4.1.27
$ git branch v4.1.27-local
$ git checkout v4.1.27-local

ノート

Linux kernel はバージョンを上げても user space 向け API は変わらないように開発されています。ただし、現実的な問題として API は変わらずとも、大きな拡張があると拡張機能に対応した設定ツール群が無く操作に難儀することがあります。デバイス・ドライバのサポートが打ち切られたり、メンテナンスが不十分なため挙動が変わることもあります。

ノート

ここで branch を作成しても、本稿で積極的に topic branch (ちょっとした実験的な変更を追跡する branch) を作成するような操作を示さないかもしれません。branch を活用すれば、変更したコードをそのまま topic branch に commit した後、変更前の branch や tag を checkout して、戻すこともできます。手で修正を戻したり、#if defined(COND) .. #endif で括りながら修正を試すより、大胆にコード修正に取り組めるはずです。 Linux kernel のソースコードを読むと、おそらく普通の開発で見る #if 0 .. #endif の様なコードは殆ど見ることは無いはずです。デバックや様々な実験は topic branch 上で行い。納得がいったら、綺麗にして本線へ merge するか、修正を施すように流れで開発されています。

make menuconfig

ソース・コード・ツリーの根にある .config ファイルの内容を make や gcc のマクロ定義値として読み込み、Linux kernel のソース・コードはコンパイルされます。.config ファイルに書かれた値を全て吟味していると、内容を把握していても数時間を要するでしょう。いずれ .config ファイルの内容のうちデバイス・ドライバ開発で興味深い部分に触れる予定です。今は、既にある .config ファイルを使ってソース・コードをコンパイルします。

$ cd linux-stable  # 前節の続きであれば不要です。
$ cp /boot/config-`uname -r` ./.config
$ make menuconfig

良くあるエラー

In file included from scripts/kconfig/mconf.c:23:0:
scripts/kconfig/lxdialog/dialog.h:38:20: fatal error: curses.h: No such file or directory
上のようなエラーが出た場合は、パッケージを追加してください。
$ sudo apt-get install libncurses-dev

ノート

uname -rで「今の」kernel version を出力します。上手く .config ファイルを流用するにはなるべく近い version で古いか同一のものを使います。

ノート

menuconfig を使う理由の一つは、古い kernel に無かった新しい機能についてデフォルト値を決めていない設定を確定させるためです。ソース・ツリーの各ディレクトリに Kconfig というファイルがあり、この中にデフォルト値が書かれています。

ノート

クロス開発では .config ファイルをどうやって手に入れるのか? arch/processor/configs/platform_defconfig *_defconfig の一覧 に格納されています。これを $ make platform_defconfig で導入します。SoC チップ向けの platform_defconfig ファイルにはチップに備えられた周辺機能をおおよそ上手く動かすのに必要な設定が書かれています。評価用ボードで試せること、あるいは Android などのシステムとして機能する様に設定されています。ただし、PC の様に何でも接続できるようになっていない場合もあります。たとえば、各種の PCI, USB デバイス・ドライバが入っていない場合があります。入っていない理由は Flash Memory に格納しきれないなど容量の問題、メーカーで評価していない等の作業量の問題、動かしてみると不具合が露見する問題(希であってほしいですが、遭遇することも多いです)等があります。

make menuconfigを実行すると次のような画面になります。すぐにコンパイルを始められるよう最低限の設定をして先に進みます。画面のスナップショットを全て示すのは大変なので、選択項目と入力内容を示しながら進めます。例えば "General setup" と書いた場合、次の画面の下線部分をカーソルキーで選択し [Enter] を押して選択することを意味します。

 .config - Linux/x86 4.1.27 Kernel Configuration
 ──────────────────────────────────────────────
  ┌── Linux/x86 4.1.27 Kernel Configuration  ──────────────────────┐
  │  Arrow keys navigate the menu.  <Enter> selects submenus ---> (or empty submenus       │
  │  ----).  Highlighted letters are hotkeys.  Pressing <Y> includes, <N> excludes, <M>    │
  │  modularizes features.  Press <Esc><Esc> to exit, <?> for Help, </> for Search.        │
  │  Legend: [*] built-in  [ ] excluded  <M> module  < > module capable                    │
  │ ┌────────────────────────────────────────┐   │
  │ │      [*] 64-bit kernel                                                         │   │
  │ │          General setup  --->                                                   │   │
  │ │      [*] Enable loadable module support  --->                                  │   │
  │ │      [*] Enable the block layer  --->                                          │   │
  │ │          Processor type and features  --->                                     │   │
  │ │          Power management and ACPI options  --->                               │   │
  │ │          Bus options (PCI etc.)  --->                                          │   │
  │ │          Executable file formats / Emulations  --->                            │   │
  │ │      [*] Networking support  --->                                              │   │
  │ │          Device Drivers  --->                                                  │   │
  │ │          Firmware Drivers  --->                                                │   │
  │ │          File systems  --->                                                    │   │
  │ │          Kernel hacking  --->                                                  │   │
  │ │          Security options  --->                                                │   │
  │ │      -*- Cryptographic API  --->                                               │   │
  │ │      -*- Virtualization  --->                                                  │   │
  │ │          Library routines  --->                                                │   │
  │ │                                                                                │   │
  │ └────────────────────────────────────────┘   │
  ├────────────────────────────────────────────┤
  │               <Select>    < Exit >    < Help >    < Save >    < Load >                 │
  └────────────────────────────────────────────┘
  1. "General setup" -> "Local version - append to kernel release" -> テキスト入力ボックスが現れるので "-local" と入力します。
  2. "< Ok >" と "< Exit >" を選択して menuconfig を抜ける操作をすると "Do you wish to save your new configuration?" というダイアログが現れるので "< Yes >" を選択します。menuconfig は終了します。

menuconfig を終えると linux-stable ディレクトリに .config と .config.old ファイルが出来上がります。差分を観察してみると、次の点に気づくでしょう。

  • 何ケ所かで行の入れ替えがある。
  • 新しい kernel で追加された機能に関係する値が設定されている。

menuconfig を使用すると、設定を一覧でき修正も楽です。しかし、変更点の追跡は困難になります。2, 3 項目の修正であれば .config あるいは *_defconfig *_defconfig の一覧) ファイルを直接修正して開発を進めるのが良いでしょう。

構築

おおよそプロセッサ数(同時実行可能な Thread 数) x 2 の並列度でコンパイルします。並列度の上限は「主記憶量 / 200Mbyte」程度にしてください。

$ make -j 4

ノート

コンパイル中に警告をいくつか見ると思います。このページに沿った操作では深刻な警告はありません。ただし、これから書こうとするドライバに警告が出るようであれば、それは実装したコードの動作が予測できなかったり、Linux kernel が panic() (スタックダンプを出して停止する) する可能性があることを示しています。

起動するように組み込む

make で構築したファイルは起動時にメモリ上に展開される kernel image、kernel に動的に組み込むことができる .ko ファイル(kernel object)、いくつかのデバッグ情報です。これらを組み込んでいきます。

$ sudo make modules_install  # .ko ファイルをインストールする
$ sudo make install  # kernel image をインストールする

ノート

header file はインストール $ sudo make headers_install (関連ドキュメント headers_install.txt) しなくて良いの? 悩むところですが、ここではインストールせず進みます。Linux kernel version が上がっても user space に見せている API は互換性を保つのが原則です。インストールしなくてもアプリケーションは何ら変わることなく構築できます。

上記の make コマンドで Linux kernel に組み込まれるモジュールと Linux kernel の起動イメージが次のようにインストールされます。

make targetインストールされるファイル・場所
modules_installカーネルに組み込むモジュール(オブジェクト) *.ko が /lib/modules/kernel_version/kernel 以下に配置されます。一つ上の /lib/modules/kernel_version ディレクトリにはモジュール間の関係や対応デバイス等を格納した modules.* ファイルが格納されます。build シンボリックリンクは kernel にリンクするモジュールが参照するヘッダファイル位置、source シンボリックリンクは kernel を構築する際に使用したソースファイル位置を示します。
kernelconfig-kernel_version, initrd-kernel_version, System.map-kernel_version, vmlinuz-kernel_version が /boot ディレクトリに配置されます。
config-kernel_version はコンパイルに使用した .config ファイルです。
initrd-kernel_version 初期化処理で使う ramdisk イメージです。今まで使っていた initrd をほぐして、中に格納されている *.ko ファイル群を差し替え、再構築されたファイルです。
System.map-kernel_versionは kernel ソース・ツリーの基底ディレクトリに作成された System.map のコピーです。シンボルとアドレスの対応表です。
vmlinuz-kernel_versionは /arch/processor/boot/bzImage のコピーです。圧縮された linux の boot イメージに起動コード /arch/processor/boot/setup.bin が付け足されたものです。

構築した Linux kernel を起動する様に grub2 boot loader を構成します。次のように grub.cfg ファイルを検索して、組み込まれた状態を確認します。手順通り進めていれば Linux 4.1.27-local と書かれた行が見つかるはずです。

$ grep -w menuentry /boot/grub/grub.cfg
        menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-7e6711c8-fd4c-4b35-a16a-c04d37e7778c' {
        menuentry 'Ubuntu, with Linux 4.1.27-local' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.1.27-local-advanced-7e6711c8-fd4c-4b35-a16a-c04d37e7778c' {
        menuentry 'Ubuntu, with Linux 4.1.27-local (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.1.27-local-recovery-7e6711c8-fd4c-4b35-a16a-c04d37e7778c' {
        menuentry 'Ubuntu, with Linux 3.19.0-25-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-3.19.0-25-generic-advanced-7e6711c8-fd4c-4b35-a16a-c04d37e7778c' {
        menuentry 'Ubuntu, with Linux 3.19.0-25-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-3.19.0-25-generic-recovery-7e6711c8-fd4c-4b35-a16a-c04d37e7778c' {
menuentry 'Memory test (memtest86+)' {
menuentry 'Memory test (memtest86+, serial console 115200)' {

確認が済んだら、 /etc/default/grub を編集します。

$ sudo nano /etc/default/grub  # 好みのエディタを使用して下さい

構築した Linux kernel を起動する様に修正します。下線をつけた箇所が修正した行です。"Ubuntu>Ubuntu, with Linux 4.1.27-local" の部分は先ほど grep で見つかった行と違う箇所があります。'>' でメニューの階層構造を表現しています。

# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
#   info -f grub -n 'Simple configuration'

GRUB_DEFAULT="Ubuntu>Ubuntu, with Linux 4.1.27-local"
#GRUB_HIDDEN_TIMEOUT=0
GRUB_HIDDEN_TIMEOUT_QUIET=false
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX=""

# Uncomment to enable BadRAM filtering, modify to suit your needs
# This works with Linux (no patch required) and with any kernel that obtains
# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef"

# Uncomment to disable graphical terminal (grub-pc only)
#GRUB_TERMINAL=console

# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
#GRUB_GFXMODE=640x480

# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true

# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_RECOVERY="true"

# Uncomment to get a beep at grub start
#GRUB_INIT_TUNE="480 440 1"

次の表は grub に施した修正の詳細です。万が一起動しない場合の緊急対応が出来る余地を追加し、起動時に表示されるメッセージを隠さず表示する修正を加えています。

修正箇所修正内容
GRUB_DEFAULT起動するイメージを選択する指定です。
GRUB_HIDDEN_TIMEOUTコメントアウトし、起動メニューを隠さず表示します。
GRUB_HIDDEN_TIMEOUT_QUIET上の変更と同様の目的で修正しました。
GRUB_TIMEOUT起動時に別の kernel を選択する時間的余裕を与える設定です。起動中にカーソルキーを押して起動する kernel を選択したり、パラメータを変更できます。
GRUB_CMDLINE_LINUX_DEFAULT起動中のメッセージを隠す指定を削除し、表示するようにしました。

grub2 boot loader を更新します。

$ sudo update-grub

特にエラーが無ければ、再起動します。

$ sudo /sbin/reboot

起動したことを確認する

おそらく、起動中にメッセージが流れるようになった以外は何か特段の変化を感じる事は無いでしょう。GUI でログインするなり ssh でログインして変化を確認します。uname -a コマンドで Linux kernel version が変わったか見てみます。構築した Linux kernel に変わっているはずです。

$ uname -a
Linux lkdqwin01 4.1.27-local #1 SMP Fri Jul 29 02:04:48 JST 2016 x86_64 x86_64 x86_64 GNU/Linux

時間が掛かった割には、大きな変化が無く少々残念かもしれません。これで、Linux kernel のソースコードを好きに弄れる環境ができあがったのです。これからデバイス・ドライバを開発する中で起動中と起動した直後、「何も変わらない。あるいは実装中のドライバに関係したハードウエアの挙動以外は何も変わらない。」というのは確実な動作をするドライバを作っていく上で、つまらないけれど重要な動作確認の一歩です。

dmesg コマンドで起動時に流れたメッセージを改めて確認しましょう。今は何も変更していないので異常と思えるメッセージは有りません。下線をつけた部分が確かに今構築した Linux kernel であることを示しています。スクロールすると見えますが構築日時 Fri Jul 29 02:04:48 JST 2016 が出力されます。組み込み開発をしているとたまに「kernel を再構築したのに何も変わらないのはなぜ?」と悩むことがあります。この構築時刻を確かめ、確かに差し替えたことを確認します。

$ dmesg
[    0.000000] Initializing cgroup subsys cpuset
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Initializing cgroup subsys cpuacct
[    0.000000] Linux version 4.1.27-local (furuta@lkdqwin01) (gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04) ) #1 SMP Fri Jul 29 02:04:48 JST 2016
[    0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.1.27-local root=UUID=7e6711c8-fd4c-4b35-a16a-c04d37e7778c ro
[    0.000000] KERNEL supported cpus:
[    0.000000]   Intel GenuineIntel
[    0.000000]   AMD AuthenticAMD
[    0.000000]   Centaur CentaurHauls
[    0.000000] tseg: 0000000000
[    0.000000] e820: BIOS-provided physical RAM map:
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[    0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000003ffeffff] usable
[    0.000000] BIOS-e820: [mem 0x000000003fff0000-0x000000003fffffff] ACPI data
[    0.000000] BIOS-e820: [mem 0x00000000fec00000-0x00000000fec00fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
... 以下省略filedmesg 出力全て ...

添付ファイル: fileVirtualBox_lkdevquest_partition_map_resize.png 198件 [詳細] filexorg.conf 280件 [詳細] filegrub 94件 [詳細] fileVirtualBox_lkdevquest_installation_type_resize.png 153件 [詳細] filedmesg-20160802.log 311件 [詳細] filevbox-055-caped.png 352件 [詳細] filevbox-090-resize.png 321件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-09-27 (水) 11:03:48 (2406d)