新千葉 ガーベージ・コレクション

FPGA マガジンやインターフェースで書けなかったこと等をちょぼちょぼ書いてます。@ryos36

vivado の dbg_hub ではまったのでメモ

Vivado で波形を見ようと mark debug したときにはまったのでそのメモ。

やろうとしたことは AXI Stream の波形を見ようとしていた。AXI Stream のクロックは Zynq から供給される。なので、そのクロックに合わせて Setup Debug を設定した。

しかし、bit stream をダウンロードしても

WARNING: [Labtools 27-3123] The debug hub core was not detected at User Scan Chain 1 or 3.
Resolution: 
1. Make sure the clock connected to the debug hub (dbg_hub) core is a free running clock and is active OR
2. Manually launch hw_server with -e "set xsdb-user-bscan <C_USER_SCAN_CHAIN scan_chain_number>" to detect the debug hub at User Scan Chain of 2 or 4. To determine the user scan chain setting, open the implemented design and use: get_property C_USER_SCAN_CHAIN [get_debug_cores dbg_hub].
WARNING: [Labtools 27-1974] Mismatch between the design programmed into the device xc7z045_1 and the probes file I:/TSDI/RGB_test/RGB_test.runs/impl_1/debug_nets.ltx.
The device design has 0 ILA core(s) and 0 VIO core(s). The probes file has 1 ILA core(s) and 0 VIO core(s).
Resolution: 
1. Reprogram device with the correct programming file and associated probes file OR
2. Goto device properties and associate the correct probes file with the programming file already programmed in the device.

というエラーが出てしまう。よくよく調べると、debug hub というモジュールにクロックが供給されていないことが原因だ。該当回路図を追って行くと、Zynq の FCLK_CLK2 から”ちゃんと”クロック供給がされている、、、、

というのはうそで、FCLK_CLK2 は Zynq の設定をちゃんとすると供給する。おそらく、ps7_init をちゃんと設定しないとクロックが出てくれない。そこで、SDK を起動して、Hello world のプロジェクトを作って、デバッグで実行。main で止まったところで、再度、bit stream をダウンロード。おーこれでちゃんとデバッグができるようになりました。ときどき vio でうまく以下なったのもこれが原因か、、、

SSLv3 のエラーだが apache.conf で解決

SSL を導入して通常のブラウザからはうまく https が見えるのだが、Smart HTTP(git-http-backend) 経由で Eclipse から import しようとするとエラーが出る。

[Wed Jul 06 15:01:32.119075 2016] [ssl:info] [pid 11614] [client 192.xxx.xxx.xxx:63694] AH02008: SSL library error 1 in handshake (server rt:443)
[Wed Jul 06 15:01:32.119169 2016] [ssl:info] [pid 11614] SSL Library Error: error:140943F2:SSL routines:SSL3_READ_BYTES:sslv3 alert unexpected message (SSL alert number 10)

ログだけ見ると SSLの v3 でエラーになっているように見える。しかし、いまや SSL の v3 は脆弱性が発見されているので使いたくない。でいろいろ調べてみると単純に apache.conf の書き方の問題。

ServerName www.sample.com

みたいに conf を書いておけばいいだけだった。いい加減に www とかにしてたのがよくなかった。
このページを発見していなければ解決できなかった。感謝。

Java - HTTPS通信が失敗するようになる: javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name - ttshikoのブログ

あと、Smart HTTP
Git - Smart HTTP
このページがかなり上位に来るのだが、Order が間違っているのか、この通りにするとうまく認証しない。ちゃんと apache の認証が通るようにしないとダメ。

ついでに SSLv3 も通さないように apache の設定をする。

        SSLProtocol all -SSLv3

確認は openssl コマンド

openssl s_client -connect www.sample.com:443 -ssl3

g++ あやまったリンクをした際の残骸

あやまったリンクをした際の残骸
記録として残してある。
reent.c
void *_impure_ptr;
newlib のリエントラントな構造を保持するための大域変数。
newlib 内の実装に必要。
libstdc++ を --use-newlib でコンパイルすると、exception の unwind に
この変数が必要となってしまう。
newlib に依存しているという誤った libstdc++ をリンクするとこの現象が出る。
一次的に回避するのに -fno-exceptions を使う。
exception を使いたいのであれば g++ が要求する unwind 用の関数を
実装する必要がある。

cxa_atexit.c
デストラクタの登録に cxa_atexit が呼ばれる。
RTOS として大域変数として登録されたオブジェクトは
そもそもデストラクタを呼ぶ契機がない。
タスクの関数内で登録されているのなら、exit の代わりに
タスク終了の API でデストラクタが呼ばれるようにしないといけない。
-fno-use-cxa-atexit でコンパイルすれば、そもそもこの関数は呼ばれない。

dso_handle.c
ダイナミックローディングされたライブラリをアンロードするときも
デストラクタが呼ばれる。その際に、(おそらく)ダミー的に本体の
オブジェクトにも dso を識別するための変数が要求される。
ダイナミックローディングを使っていないのに、上の cxa_atexit の
第3引数で必要とされるため、自動的に要求されるようだ。
-fno-use-cxa-atexit で回避可能。

C++ を embedded な環境でつかう

結局、素の C++ を使うのがベスト。うっかりすると素ではなくていろんなものに依存するので注意。たとえば arm-xilinx-linux-gnueabi-gcc/g++ これは当然、Linux 環境に依存する。だから単純に printf とかすると Linux の /usr/include/stdio.h の printf を使おうとしたりする。
arm-xilinx-eabi-gcc/g++ 。これは(xilinxが) newlib + libstdc++ に(意図的に)依存させて作っている。したがって、printf とかすると newlib の stdio.h の printf を使おうとしたりする。なので、newlib が要求する Unix システムコール(もどき)のシミュレーションを(自分で作ったライブラリを)用意する必要がある。例えば open とか read/write とか close とか。xilinx はこれを Standalone と称して用意している。さらに、リンク時には、”コンパイラを作った時の”環境に依存する crt (C RunTime ?) をリンクする。xilinx は作った時に何も考えていなかったのか、空の crt がリンクされる。crt にはシステムの初期化用の _init が含まれる。
embedded な環境で使うには -nostdlib を指定すると、crt やら libc libstdc++ やらをリンクしない。
g++ でコンパイルするとデフォルトではデストラクタの登録に __cxa_atexit を使おうとする。cxa はどうやら c++(cxx) abi の略のようだ。g++ では -fno-use-cxa-atexit を指定すると cxa_atexit を使わないオブジェクトを生成することが出来る。__aeabi_atexit が undefine の時はこれで”一時的に”解決する。全部解決したと思わない方がよい。RTOS などの設計にもよるが、いつデストラクタを呼ぶのかはちゃんと考えないといけない。タスクやスレッドが終わった時にどうするのか?が主な注意点だろう。これは RTOS の設計。
libc を自分で設計するならリエントラントに設計する必要があるかどうか?それらの情報どうするかは考えないといけない。g++ は exception を使う設定にしておくと、__gxx_personality_v0 と __cxa_end_cleanup の実装を要求される。これはいずれも exception ハンドラに関連する関数。特に __gxx_personality_v0 は try catch を使うなら実装が必須。最近では setjmp/longjump は使わないみたいだ(未確認)。下のblogが役に立ちそう。

g++の例外を捕まえよう!!(素手で)

exception を使わないなら(不便になるけど)-fno-exceptions を使えばよい。結局、g++ ではオプションで次の設定をしておけば(コンパイラ自身が持っている環境を無視するので)だいだい使える。

-nostdinc -nostdlib -fno-use-cxa-atexit -fno-exceptions

さぁこれで vx-schemeコンパイルがどこでもできるんじゃないかな?

やってはいけないこと

そんでもって -nostdlib を選択したということはコンパイラが持つ libc や libstdc++ を使わないということ。なので、-lc なんかしちゃだめ。-lm も当然ダメ。中途半端にライブラリをリンクすると dso_handle がないとか言われる。あと __impure_ptr 。これは newlib の環境内のリエントラントな構造を保つ大域変数。つまり newlib が前提。newlib を前提としてコンパイルされた libstdc++ は exception の回収にこのポインタを使う。だから、そんなことが起こったらきっと環境が間違っている。exception を使わないことがわかっているなら -fno-exceptions で回避できる。もし、使うなら、自分で unwind するための関数である 、__gxx_personality_v0 と __cxa_end_cleanup の実装が必要。
まちがっても、いろんなものを”くっつけて”解決しようとしないように。私は dummy.c というファイルを作って、知らない関数や変数をいっぱい定義して回避している”プロジェクト”を見たことがある。当然、崩壊してたね。まぁ趣味ならいい気はする。

new や delete

これをつかうと動的にメモリ確保開放を必要とする。RTOS で使うときは注意。動的にメモリ獲得するということは結局ガベージコレクション(的な現象)を生む。これはスクリプト言語を使わなくても malloc を使えば起こるということ。malloc の実装にもよるけど、メモリが足りなくなったらエラーになるならまだよいが、他のタスクが解放してくれるのを待つという実装になっていると RTOS の意味がなくなる場合(ケースバイケースだが)がある。だからやってはいけないというわけではなくて、注意。
まぁ TCP/IP つかっちゃうと結局動的にメモリ確保をするので(mbuf とかね)ここも本来注意なんだけど、、、最近では気にする人はいなくなっちゃたね。
new や delete を使うと operator が足りないと言われるので(言われなかったら何か怪しい libstdc++ をリンクしているぞ。危険)自分で実装する。malloc で実装してもよいし、簡単に自分で RTOSAPI を使ったり、単純な配列を使ったりしてもよい。要は delete と連動していればよい。
あと、うろ覚えだけど、クラスに new や delete を関連付けることが出来たような、、、、
placement new と delete(2)

placement new

RTOS ではこちらがおすすめ。new や delete のオペレータを使わない。
placement new と delete(1)

自分専用の gcc を作る

何度かトライしたけどめちゃめんどくさい。みんないい加減にやっている(やっていた)。しかし、Android や Yocto がうまくコンパイラコンパイルを隠ぺいして開発環境を自動的に作ってくれる環境を作ったので、みんな何も考えずにできるようになったね。ぱちぱち。2000 の初めにはなんか自分で gcc をつくらなきゃいけなかったので、毎晩、nightly build を追ってた。特に sh。
Linux 用のコンパイラを作る手順はざっと書くと次のような感じ

  • build 用のコンパイラを作る(i386 -> i386 ってことね。最近では x64 -> x64 かな)
  • cross 用のコンパイラをとりあえず作る。たとえば arm-unkown-eabi-gcc みたいなもの。newlib に依存してもしなくてもよい。これはいずれ捨てる。
  • arm-unkown-eabi-gccLinux カーネルコンパイルする。これで Linux の一時環境が出来た。この時点でやろうと思えば Linux のアプリは作れる。APILinuxシステムコールだけだが。ここで用意されるのは Linux が用意する include の類でこれをどっかクロスコンパイラ用 root にインストールする。
  • libc をつくる。Linux の環境とコンパイラがあれば libc が作れる。作れるはずなのだが、、、libc を作るときに libc 入りのコンパイラを要求されたり、例によって途中でバージョンの依存関係でエラーになったりと、苦労する。jこれを Linux の クロスコンパイラ用 root にインストール。ここを明示的に参照することで Linux アプリが書ける。(はず)
  • Linux の クロスコンパイラ用 root を元に cross 用のコンパイラを作り直す。arm-linux-gnueabi-gcc みたいもの。このクロスコンパイラは include とか lib とかはこのクロスコンパイラ用の root を"自動的に"参照することになる。
  • 出来たコンパイラで次々とライブラリをコンパイル・インストールする。そうすると、クロスコンパイラ用 root がいつのまにか Linux の root のようになる。これをファイルシステムにすればよい。これはオールドスタイルの root fs だ。
  • 出来た クロスコンパイラ用 root は実は i386 で動くクロスコンパイラが出来てたりする。だから、これをファイルシステムにしてしまうと i386 オブジェクトが含まれることになる。そこで、deploy 用の root fs を別に作る。ここにこつこつライブラリなどをインストールすれば本当の root fs ができる。

これを gcc のバージョン違いやいろんなライブラリを作るときのエラーの回避なんかをしてると、らちが明かない。Yocto は上を全部自動でやってくれる。そして、注目したいところだけ、自分でつくりこめばいいのだ。これは楽だね。

基本的には RTOS も上の手順を踏めば、正しく標準ライブラリを組み込んだ gcc ができる(はず)。

ARM の EABI とか newlib とか

あまりまとまっていないけど最近の成果をメモ。わすれちゃうからね。

XilinxSDK 用の gccgdb だけ再コンパイルしようとしたけどだめだった。もう全部コンパイルしないといけないみたい。結構めんどくさい。とはいえ、シェルプロがあるようなのでそれを一発動かせばよさそうであるのも事実。この SDK 用の gcc では g++ が使える。特に arm-xilinx-eabi- の方はどうしているのだろうとちょっと調べてみた。普通と言えば普通なんだけど、newlib を使っている。newlib を使うと、open や write などの Unixシステムコールが用意されているものとして libc を作ってくる。あとはこれらのシステムコールをシミュレーションすれば(用意すれば)c++ はできあがる。実際に、SDK では普通に c++ を選択できる。Eclispe での設定は次のようになっている。

-Wl,--start-group,-lxil,-lgcc,-lc,-lstdc++,--end-group
  • lstdc++ が指定されているが、 -nostdlib は指定されていない。つまり crt0 なんかがくっつく。crt0 はほとんど何もしていない。だから本来は crt0 なんかくつけないように -nostdlib を使用するべきなのだ。がそうはなっていない。理由は恐らく _init の存在。なぜか _init は crtbegin の中にあったりする。この _init はシステムの初期化なので本来は OS が持っていなければならないはずだ。そこが手抜きされている。っていうかなにリンクされているかわからないからほんとはすべて自分でコントロールすべきだよ。

まぁそんなこんなで newlib が要求するシステムコールは bsp 内の ps7_cortexa9_0/libsrc/standalone_v5_3/src にある。write なんてかなり手抜き。まぁいいのか。

リンカーで特徴的なのは .ctors とか .dtors で(コンストラクタとデストラクタかな)、さらに初期化ルーチンの preinit_array とinit_array 。C だけならあまりこの辺は気にしなくてよいのだけど、c++ を使うなら、この preinit_array と init_array に登録された関数をちゃんと呼ばないといけない。newlib では misc の init.c で __libc_init_array を呼べばよい。実際、SDK の main の前でよばれている。(xil-crt0.S)。もー crt0.S を用意するなら -nostdlib を設定すればいいのに、、、この __libc_init_array から _init が呼ばれているが、これは main に入る前の _init なんで(くりかえすけど) OS が用意するもの。SDK は用意しないで gcc の crt をリンクすることで解決している。まぁ弊害はないからいいのか?

c++ でめんどくさいのはグローバル変数のオブジェクト。これは gcc のバージョンにもよるが、4.9.1 だと

__static_initialization_and_destruction_0(int, int)

という関数が出来た。init_array 各関数をコールすることで呼ばれる。そして、このとき cxa_atexit 経由でデストラクタが登録される。いま検索したら

-fno-use-cxa-atexit

というオプションをつけると登録されないらしい。なんだよ~~~。意味がなくなりつつあるけど、続けて書くよ。

つまり終了処理の時にデストラクタを呼ぶ。終了処理は exit の時だけではなく、動的ライブラリのアンロードの時も呼ばれる。動的ライブラリを使っていないのに動的ライブラリの事を気にしなくてはいけなくなるのよ(あーでも -fno-use-cxa-atexit を使うと解決するみたいよ)。

動的ライブラリは各ライブラリに handle が割り当てられて、本体も仮想的に動的ライブラリ扱いされるので、main に dso_handle が必要になる。そして、デストラクタ登録のために cxa_atexit が呼ばれる。これらは newlib に用意されているから本来あまり気にしなくてよい。cxa_atexit などの必要な関数というのは EABI で決められているらしい。

あと、もう一つ、gcc は void *_impure_ptr; も用意しなければならない。これは再入可能な環境を保持していくもののようで、 newlib は reentrant な環境も用意していているので、newlib を使うとばっちりそろっている。

ということで、SDK ちょっとへんだけど普通に g++ が使えるという話。めでたしめでたし。

tkernel みたいな

tkernel みたいなのはちょっとめんどくさくなってくる。どういうわけか malloc を持っている。まぁそもそも libc とはなじまないから -nostdlibc だよね。最初は -nostdlibc を削除して SDK のように -lc をつかった。はい。できました。でも、これはよくなくて、crtX.o とか atexit とか、あまり tkernel の OS の事を考えてないものがくっつく。malloc なんてリンク順でかろうじて tkernel のが呼ばれる。危ない。

だから、この手の RTOS はやっぱり -nostdlibc で自前で crtX.o や libc をつくらないといけない。

_impure_ptr は newlib にその構造体が定義されていて、それを指すポインタになっている。 ./libsupc++/vterminate.cc から参照されている。システムでどのように reent の構造を用意するかということみたいなので、とりあえず、変数だけを用意しておく。(おい!! > 自分)

なんとなくだが、libstdc++ のコンパイルに失敗している気がするぞ。たしかに configure に --with-newlib がある。

usb_modeswitch と FS01BU

FS01BU は普通に USB Host につなぐと 1c9e:98ff で Mass Storage と認識される。usb-modeswitch を使うとモードを変えることが出来る。usb_modeswitch の本家からusb-modeswitch-data をとってくると 1c9e:98ff のデータがある。それを使う。

> usb_modeswitch -v 0x1c9e -p 0x98ff -c usb_modeswitch.d/1c93:98ff

これで vendor 固有のやりとりをして 1c9e:6801 に変更してくれる。1c9e:6801 になったら、今度は、modprobe で usb_serial を”無理やり" わりあてる。そのまえに 1c9e:6801 のエンドポイントを簡単に見てみる。(lsusb -v で詳しく見れるはず)。lsusb -v の出力ではないけど、自分で解析した結果は次の通り。

inteface:00 ff ff ff
   81: bulk
   01: bulk
inteface:01 ff ff ff   
   82: interrupt
   83: bulk
   02: bulk
inteface:02 ff ff ff
   84: bulk
   03: bulk
inteface:03 08 06 50
   04: bulk
   85: bulk

みたいな感じ。ff ff ff は USB のクラス等なのだが未定義ということになる。08 06 50 は Mass Storage。そこで、modprobe で usb serial を指定すると、よくわからないものすべてを usb serial に割り当てるようだ。kernel のソースを読むと vendor id と product id しかみていない。つまり、順に未定義の inteface すべてに usb serial を割り当てる。結果として ttyUSB0, ttyUSB1, ttyUSB2 ができる。素性のわかっている 08 06 50 には usb serial は割り当てないようだ。

usb serial の general に vendor id と product id 以上の割り当てポリシーに関する解像度はないので、すべてが usb serial になってしまう。ttyUSB2 は AT コマンドを受け付けるようなので (cu -l /dev/ttyUSB2 で確認可能。ATE1 でecho。ATI で情報が得られる)
、適当に遊べる。atd は使えなかった(そういうものじゃないらしい)。

じゃ、あとの interface 0 と 1 をアサインした ttyUSB0 と ttyUSB1 の役割は何なのだろうという疑問がわく。82 が interrupt なので、データの送受信は 82 02 でやるのかな?

ということで、ubuntu を upgrade するとうまくいくという記述をちらほら見かけますが、これは恐らく、usb_modeswitch のデータが更新されたためですね。

メモ:DNS の設定で警告

権威DNSサーバーの設定不備による情報流出の危険性と設定の再確認について(2016年1月12日公開)
jprs.jp から警告を受けたので

options に allow-transfer を追加

        allow-transfer { 192.168.0.XX; };

セカンダリだけにトランスファをするのが正しいらしい。