ARM Linuxのブート方法は3種類あって、一番古い方式はもう使われていません。自作エミュレータの内蔵ブートローダで使っているのは2番目に新しい、ATAGSと呼ばれる方式です。
最新の流行はDevice Treeを使う方式らしいので、内蔵ブートローダを改造して試してみました。が、なぜかカーネルが異常なアドレスにアクセスして死にます。アドレスを調べても、仕様書にないレジスタです。
発動条件を調べるとDevice Treeを有効(CONFIG_MACH_VERSATILE_DTを有効にする)にして、Device Treeを使ってブートするとハマるようです。
Linuxカーネルのコードを見てもATAGSで起動したときと、Device Treeで起動したときに実行されるコードがなぜか違うし、どういう意味なんだこれ…。
Linuxカーネルのコードに出てくるレジスタ名で調べていたら、どうもmach-integratorにあるコードと同じレジスタアドレスを使っているように見えます。
下記がIntegratorのレジスタアドレス定義です。
#define IRQ_STATUS 0
#define IRQ_RAW_STATUS 0x04
#define IRQ_ENABLE 0x08
#define IRQ_ENABLE_SET 0x08
#define IRQ_ENABLE_CLEAR 0x0C
#define INT_SOFT_SET 0x10
#define INT_SOFT_CLEAR 0x14
#define FIQ_STATUS 0x20
#define FIQ_RAW_STATUS 0x24
#define FIQ_ENABLE 0x28
#define FIQ_ENABLE_SET 0x28
#define FIQ_ENABLE_CLEAR 0x2C
で、下記がDevice Treeで起動したときのVersatile PB/ABのレジスタアドレス定義です。コピペだと思えるくらいに似ています。
#define IRQ_STATUS 0x00
#define IRQ_RAW_STATUS 0x04
#define IRQ_ENABLE_SET 0x08
#define IRQ_ENABLE_CLEAR 0x0c
#define INT_SOFT_SET 0x10
#define INT_SOFT_CLEAR 0x14
#define FIQ_STATUS 0x20
#define FIQ_RAW_STATUS 0x24
#define FIQ_ENABLE 0x28
#define FIQ_ENABLE_SET 0x28
#define FIQ_ENABLE_CLEAR 0x2C
#define PIC_ENABLES 0x20 /* set interrupt pass through bits */
こちらが正しいレジスタアドレス定義です。ATAGSで起動した場合はこちらのアドレスが使われます。
#define SIC_IRQ_STATUS 0
#define SIC_IRQ_RAW_STATUS 0x04
#define SIC_IRQ_ENABLE 0x08
#define SIC_IRQ_ENABLE_SET 0x08
#define SIC_IRQ_ENABLE_CLEAR 0x0C
#define SIC_INT_SOFT_SET 0x10
#define SIC_INT_SOFT_CLEAR 0x14
#define SIC_INT_PIC_ENABLE 0x20 /* read status of pass through mask */
#define SIC_INT_PIC_ENABLES 0x20 /* set interrupt pass through bits */
#define SIC_INT_PIC_ENABLEC 0x24 /* Clear interrupt pass through bits */
私もそんなに詳しいわけではありませんが、Versatile AB/PB (DUI0225D) とIntegrator CP (DUI0159B) は全く別のボードだと思うので、恐らくDevice Treeに対応した人が間違えたのでしょうね…。
気になったのでqemuで試してみましたが、やはりエラーが出ます。もしかして動作確認してないのかなあ??
しかしqemuさんは強い子でして、明らかに未定義領域にwriteされたのに警告を出すのみで、とにかく先に突き進んでくれます。それで結果的に動くからスゴイですよね…。
$ qemu-system-arm -kernel linux-4.1.13/arch/arm/boot/zImage \ -dtb linux-4.1.13/arch/arm/boot/dts/versatile-pb.dtb \ -M versatilepb \ -append 'console=ttyAMA0' \ -nographic -serial mon:stdio Uncompressing Linux... done, booting the kernel. vpb_sic_write: Bad register offset 0x2c★★★エラー出てる★★★ Booting Linux on physical CPU 0x0 Linux version 4.1.13 (katsuhiro@vbox) (gcc version 4.9.2 (GCC) ) #4 Sun Dec 6 01:46:36 JST 2015 CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00093177 CPU: VIVT data cache, VIVT instruction cache Machine model: ARM Versatile PB
★を付けたところ(vpb_sic_write〜 と出ている部分)がqemuの警告です。
Facebookでの2013〜2014年辺りの書き込みを、この日記にも転記しておきました。
大した数ではないだろうと甘く見ていたら意外と数が多くて、結局50個近くのエントリを作る羽目になりました。うーん、疲れた……。
ドコモ、NOTTV/モバキャスを2016年6月に終了 周波数は返還 - ITmedia Mobileを読んで。
ニュース見てnottvの開始時期いつだっけ?と思って調べたら2011年でしたから、約5年で終わってしまったんですね。
テレビ放送は放送局の都合で番組が流れるだけですが、VoDなら見たい番組をすぐに見ることができるわけで。どちらも有料なら、テレビ放送は選ばないですよね…。
メモ: 技術系の話はFacebookから転記しておくことにした。
目次: GCC
自作ARMエミュレータでLinaroのクロスコンパイラで作ったバイナリを動かすまでは道が遠すぎて(ARMv6, Thumb-2, ARMv7の実装が要る)、すぐに出来そうにないので、
ARM9用のgccとglibcをビルドすれば良いんじゃねー?と軽い気持ちで始めたのですが、エラー大量発生&何を変えたら直るかさっぱりわからず、悪戦苦闘でした。
一応libc付き&スタンドアローンで動作するARM用クロスコンパイラが作れましたが、疲れましたね…。
Linaroはcrosstool-NGを使っているようです。次はこれも試してみようと思います。自前でやって苦戦した今だからこそ、ビルド自動化ツールのありがたさが理解できるはずです。
適当にgccとlinuxのソースtarballをGithubに叩き込んだら、Githubに「デカいファイル置くな」って怒られた…。
remote: warning: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com/ remote: warning: See http://git.io/iEPt8g for more information. remote: warning: File gcc-shared/gcc-4.9.2.tar.bz2 is 85.77 MB; this is larger than GitHub's recommended maximum file size of 50.00 MB remote: warning: File linux-headers/linux-3.18.11.tar.xz is 77.21 MB; this is larger than GitHub's recommended maximum file size of 50.00 MB remote: warning: File gcc-shared/gcc-4.8.4.tar.bz2 is 82.23 MB; this is larger than GitHub's recommended maximum file size of 50.00 MB
メモ: 技術系の話はFacebookから転記しておくことにした。
このサイトの日記には「permalink」というリンクを出していて、リンク先はあらかじめ保存しておいたHTMLファイルへのリンクとなっています。
内容は同じですが、動的に生成するトップページに比べ、permalink先は単なるHTMLファイルですので表示が速いはずです。実はきちんと測ったことないので、どれくらい速いかまでは知らないですけど…。
で、permalinkのリンク先であるHTMLファイルは、今まで記事を書くごとに手動で更新していたわけです。しかし面倒だし良く忘れてリンク切れになるし、ロクなことがないので、自動更新するように変えました。
現状は自宅サーバから更新を掛けており、昼と夜の1日2回更新です。たしかSakuraのサーバでもcrontabを設定できたはずですが、書き方が悪いのか動かなかったので放棄しました。
自作エミュレータに外部とのアクセス手段を足そうと思い、ARM Versatileに載っており、かつLinuxのドライバが存在するハードを調べてみたら、
NORフラッシュなら簡単かなーと思って調べ始めたら、ちょっと甘かったです。
Versatileのメモリコントローラの仕様書には16bitフラッシュの型番が載っていて「対応してる」と書いてあります。つまり16bitフラッシュをエミュレーションすれば良いはずです。
NORフラッシュにはコマンドという概念があって、特殊なアドレス+特殊なデータをwriteすると、コマンドとして解釈されます。コマンドによって、容量とか8bitなのか16bitなのか調べたり、ブロックをEraseしたりできるわけです。
試しにLinuxのドライバを動かして、CFIというJEDECの規格に載っているQueryコマンド(CPUからFlashへ、容量やらビット幅を尋ねるコマンド)を送るとき、どんな動きをしているか見ると、
このように一見32bitに見えて、コマンドのデータが全然違う値なので、最初はさっぱり意味がわかりませんでした。
もしデータ幅と同じ32bitフラッシュが接続されているのであれば、下記の図のように接続されていて、使用するコマンドは32bitフラッシュ用のデータになるはずです。
しかし仕様書にはどう見ても16bitフラッシュの品番が書いてありますし、実際に発行しているコマンドも16bitフラッシュ用のデータです。
ハードに詳しい方はお気づきかもしれませんが、おそらくCPUとNORフラッシュの間にいるメモリコントローラが一枚噛んでいて、下記の図のように16bitフラッシュに2発同時アクセスして、32bitデータを扱えるようにしていると思われます。
アドレス線は共通(ただし下位1bitは捨てる)で、データはコントローラ側で分割(Write時)、結合(Read時)される仕様です。
CPUから見ると1度に32bitのデータを扱えるように見えますが、あくまでも接続されているのは16bitフラッシュですので、アドレスとデータは16bitフラッシュ用のものにしなければなりません。1つ目のフラッシュと2つ目のフラッシュ双方にデータを送る必要があるため、上位bitと下位bitの両方にデータを入れていた訳です。
とまあ、こんな具合でreadは簡単(?)に出来ましたが、writeを調べたらerase, writeのパターンが多くて、ちょいと大変そうです…。
Flash ROMのハードウェア仕様上のアドレスは、ワードアドレス(つまり2バイトでアドレスが1増える)ですが、仕様書のコマンドの説明はバイトオフセットで書いてありました。少なくともIntelとMicronの仕様書は。
従ってエミュレーションする際はバイトアドレスを使った方が、仕様書と数字が一致して読みやすいです。ハードウェアのアドレス線がどうなっていようが、ほとんど気にする必要はありません…。
< | 2015 | > | ||||
<< | < | 12 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | - | - |
合計:
本日: