Intel EdisonにXenomaiを入れる(ただしWiFiなし...) − (本題)

前回に続き、EdisonにXenomaiを入れていきます。

Xenomai用のパッチを作成する

まず、コンパイルに必要なEdison用のXenomaiパッチを作成していきます。最初にXenomaiのコードをとってきましょう。以下では、Edison、Linuxのソースコードを展開したディレクトリを基準としています。

$ ls
edison-src                       linux-yocto-3.10-3.10.32.tar.bz2
linux-yocto-3.10-3.10.32         upstream_to_edison.3.10.32.patch
linux-yocto-3.10-3.10.32-edison
$ git clone git://git.xenomai.org/xenomai-3.git
Cloning into 'xenomai-3'...
remote: Counting objects: 120758, done.
remote: Compressing objects: 100% (20429/20429), done.
remote: Total 120758 (delta 98188), reused 119251 (delta 96934)
Receiving objects: 100% (120758/120758), 273.37 MiB | 625.00 KiB/s, done.
Resolving deltas: 100% (98188/98188), done.
Checking connectivity... done.
$ ls
edison-src                       linux-yocto-3.10-3.10.32.tar.bz2
linux-yocto-3.10-3.10.32         upstream_to_edison.3.10.32.patch
linux-yocto-3.10-3.10.32-edison  xenomai-3
$ 

続いて、元のYocto Projectのカーネル3.10.32に対してXenomaiのパッチを当てます。Xenomaiパッチを当てるにはドキュメントにあるように、スクリプトを実行してやります。パッチを当てたら、分かるようにディレクトリ名を変更しておきましょう。

$ xenomai-3/scripts/prepare-kernel.sh --help
usage: prepare-kernel --linux= --ipipe= [--arch=]
 [--outpatch= [--filterkvers=y|n] [--filterarch=y|n]] [--forcelink] [--def
ault] [--verbose]
$ xenomai-3/scripts/prepare-kernel.sh --linux=linux-yocto-3.10-3.10.32 \
    
checking file arch/x86/Kconfig checking file arch/x86/Kconfig.debug checking file arch/x86/include/asm/apic.h ... checking file mm/mmu_context.c checking file mm/mprotect.c checking file mm/vmalloc.c $ mv linux-yocto-3.10-3.10.32 linux-yocto-3.10-3.10.32-ipipe $ ls edison-src linux-yocto-3.10-3.10.32.tar.bz2 linux-yocto-3.10-3.10.32-edison upstream_to_edison.3.10.32.patch linux-yocto-3.10-3.10.32-ipipe xenomai-3 $
今度はXenomaiパッチを当てたカーネルソースコードにEdisonパッチを当ててやります。ここで使用するのは、前回作成した3.10.32用のパッチです。
$ cd linux-yocto-3.10-3.10.32-ipipe/
$ patch -p1 < ../upstream_to_edison.3.10.32.patch
patching file Documentation/kernel-parameters.txt
patching file arch/x86/Kconfig
Hunk #1 succeeded at 446 (offset 4 lines).
...
patching file kernel/power/process.c
patching file kernel/printk.c
patching file sound/soc/codecs/sn95031.c
$ find . -name "*.rej"
./arch/x86/kernel/apic/io_apic.c.rej
$ 
このとき、ひとつのファイル(arch/x86/kernel/apic/io_apic.c)でパッチ適用失敗となります。これについては、手動で修正してやります。2656行目から以下のように修正します。
static struct irq_chip ioapic_chip __read_mostly = {
        .name                   = "IO-APIC",
        .irq_startup            = startup_ioapic_irq,
        .irq_mask               = mask_ioapic_irq,
        .irq_unmask             = unmask_ioapic_irq,
        .irq_ack                = ack_apic_edge,
        .irq_eoi                = ack_apic_level,
        .irq_set_affinity       = native_ioapic_set_affinity,
        .irq_retrigger          = ioapic_retrigger_irq,
#ifdef CONFIG_IPIPE
#ifdef CONFIG_SMP
        .irq_move               = move_xxapic_irq,
#endif
        .irq_hold               = hold_ioapic_irq,
        .irq_release            = release_ioapic_irq,
#endif
};
        ↓↓↓↓↓
static struct irq_chip ioapic_chip __read_mostly = {
        .name                   = "IO-APIC",
        .irq_startup            = startup_ioapic_irq,
        .irq_mask               = mask_ioapic_irq,
        .irq_unmask             = unmask_ioapic_irq,
        .irq_ack                = ack_apic_edge,
        .irq_eoi                = ack_apic_level,
        .irq_set_affinity       = native_ioapic_set_affinity,
        .irq_set_wake           = ioapic_set_wake,
        .irq_retrigger          = ioapic_retrigger_irq,
#ifdef CONFIG_IPIPE
#ifdef CONFIG_SMP
        .irq_move               = move_xxapic_irq,
#endif
        .irq_hold               = hold_ioapic_irq,
        .irq_release            = release_ioapic_irq,
#endif
        .flags                  = IRQCHIP_SKIP_SET_WAKE,
};
修正したら、パッチ適用時に出来た余計なファイルを削除します。Emacsで編集した場合には、編集時のバックアップファイル(arch/x86/kernel/apic/io_apic.c~)も消しましょう。その後パッチを当てたことを忘れないように、ディレクトリ名も変更しておきましょう。
$ find . -name "*.rej" -exec rm {} \;
$ find . -name "*.orig" -exec rm {} \;
$ cd ..
$ mv linux-yocto-3.10-3.10.32-ipipe linux-yocto-3.10-3.10.32-ipipe-edison
$ ls
edison-src                             linux-yocto-3.10-3.10.32.tar.bz2
linux-yocto-3.10-3.10.32-edison        upstream_to_edison.3.10.32.patch
linux-yocto-3.10-3.10.32-ipipe-edison  xenomai-3
$ 
これで、Edison用のXenomaiパッチを作ることが出来ます。作成したパッチは前回作成したパッチと同じ場所にコピーしましょう。これでパッチの作成が完了です。
$ diff -Narup *-3.10.32-edison *-3.10.32-ipipe-edison > xenomai-3.0-3.10.32.patch
$ cp xenomai-3.0-3.10.32.patch edison-src/device-software/meta-edison/recipes-kernel/linux/files/
$ 

コンパイル環境の修正

カーネルのビルド時に作成したXenomaiパッチが適用できるよう、linux-yocto_3.10.bbappendを修正してやります。修正は以下の赤い部分を追加するだけです。
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
COMPATIBLE_MACHINE = "edison"
LINUX_VERSION = "3.10.32"
SRCREV_machine = "61dde96f97bb5b1ed4c11caf9a857d55ad8f6e17"
SRCREV_meta = "e46e0e44708e23533f8df904cebf23a352e9053a"

SRC_URI += "file://defconfig"
SRC_URI += "file://upstream_to_edison.3.10.32.patch"
SRC_URI += "file://xenomai-3.0-3.10.32.patch"
do_configure() {
  cp "${WORKDIR}/defconfig" "${B}/.config"
}
do_kernel_configme() {
  cp "${WORKDIR}/defconfig" "${B}/.config"
}
do_patch() {
  cd ${S}
  git apply "${WORKDIR}/upstream_to_edison.3.10.32.patch"
  git apply "${WORKDIR}/xenomai-3.0-3.10.32.patch"
}
次に、WiFi関係を修正します。 EdisonのWiFiおよびBluetoothのカーネルモジュールは、カーネルとは別にedison-src/broadcom_cwsディレクトリに用意されています。カーネルのビルド後、これらのモジュールをビルドして組み込んでいます。 現状、WiFiモジュールはXenomaiカーネル上でそのままでは動作しないため、今回ははずします。 なお、Bluetoothモジュールはかろうじて動作はしますが、不安定です。 WiFiモジュールのビルドをしないようにするには、edison-src/device-software/meta-edison-distro/recipes-core/imagesディレクトリにあるedison-image.bbを修正します。 81行目から以下のように赤い部分をコメントアウトします。Bluetoothモジュールもビルドしない場合はbcm43340-btとbluetooth-rfkill-eventの行もコメントアウトします。 (ちなみに、Edison起動後にWiFiを使わなければ問題ないので、この修正は必須ではありません。)
# Wifi firmware
#IMAGE_INSTALL += "bcm43340-fw"
# Bluetooth Firmware patch for 43340 and its patch utility
IMAGE_INSTALL += "bcm43340-bt"
# service daemon that listens to rfkill events and trigger FW patch download
IMAGE_INSTALL += "bluetooth-rfkill-event"
# Wifi driver built as a kernel module
#IMAGE_INSTALL += "bcm43340-mod"
出来上がったEdisonのイメージをEdisonに書き込んだ時には、次の起動時に一旦全体の設定が行われます。その時WiFiの設定も行われ、その時にモジュールが組み込まれます。Xenomaiを組み込んだカーネルではこのときハングしてしまいますので、以下ではこの設定をしないように修正します。 Edisonへのイメージの更新方法には2通りあり、USB経由でファイルをコピーして"reboot ota"する方法と、dfu-utilを使う方法があります。それぞれ動作するスクリプトが異なり、 前者はedison-src/device-software/meta-edison-distro/recipes-core/ota-update/files/ota-update.sh 後者はedison-src/device-software/meta-edison-distro/recipes-core/first-install/files/first-install.sh となります。 それぞれファイルの最後から9行目付近の「# Setup Access Point SSID and passphrase」以下2行をコメントアウトします。
# Setup Access Point SSID and passphrase
#setup_ap_ssid_and_passphrase
#fi_assert $? "Generating Wifi Access Point SSID and passphrase"
これでひとまず修正は完了です。

カーネルとイメージのビルド

あとはカーネルをビルドし、Edisonのイメージを構築します。 念のため、カーネルをcleanしてからビルドします。
$ cd edison-src/build
$ bitbake virtual/kernel -c clean
$ bitbake virtual/kernel
このとき、ビルドエラーが発生します。これは使用したカーネルの設定ファイル(.config)が元のEdisonオリジナルのものであり、この中にはXenomai関連の設定項目がないためです(内部的にmake oldconfigを行い、新しい項目では入力を求めているため)。 ここでは明示的にカーネルの設定を行います。
$ bitbake virtual/kernel -c menuconfig
この中では、以下の設定を行います。
  • [General setup]--->[Local version - append to kernel release]
    • "-poky-edison"となってますので、Xenomaiだと分かるように設定しましょう。たとえば"-poky-edison-ipipe"など。
  • [Xenomai/cobalt]
    • 有効にします。
  • [Processor type and features]--->[Interrupt pipeline]
    • 有効にします。([Xenomi/cobalt]が有効だと、ここもすでに有効になっています。)
  • [Power management and ACPI options]--->[CPU Frequency scaling]--->[CPU Frequency scaling]
    • 無効にします。
  • [Power management and ACPI options]--->[CPU idle PM support]
    • 無効にします。
  • [Device Drivers]--->[Network device support]--->[Wireless LAN]
    • 無効にします。(WiFiモジュールのビルドのところと同様、Xenomai上で使用しなければ無効にしなくてもいいけど…)
さて、後はもう一度カーネルのビルドとEdisonイメージの作成です。
$ bitbake virtual/kernel
...
$ bitbake edison-image
...
$ ../device-software/utils/flash/postBuild.sh
以上で、Edison用のXenomaiカーネルのビルドが出来ました。出来上がったtoFlashディレクトリ内のファイルをEdisonに転送し、Edison上で"reboot ota"で再起動すると、Xenomaiカーネルで起動するはずです。

さいごに

現状、以下の課題が残っています。
  • Xenomai用のプログラムを作成するためのビルド環境を整える
  • Bluetoothモジュールが不安定なので、修正が必要。
  • WiFiモジュールを動作できるよう、修正が必要。
いつになるか分かりませんが、少しずつやっていこうと思います。 何か情報がありましたら、教えていただけるとありがたいです。 ではでは。