あるごリズム備忘録

学んだことの記録と日記

組み込みOS(第7回)

ステップ7の内容

割り込み処理を実装する。前回までのシリアル入力の受取りはビジー・ループによって行われていたが、今回はシリアル割り込み処理によるものに変更する。

割り込み入力ピン

部割り込みに対しては、ピンへの入力によって割り込みハンドラを呼び出す。
ピンの数が外部からの割り込み出力の種類より多い場合はそれぞれのコントローラにピンを割り当てればよい。しかし、ピンが1つしかない場合は、複数のコントローラの出力のORをピンへの入力とし、各コントローラの持つ割り込み関連のレジスタを、ハンドラ内で調べて処理を変更する。

割り込みコントローラ

複数の出力をOR論理で結合してピンに伝えるが、それぞれの割り込みの優先度などの制御ができる。

割り込み処理の流れ

割り込みが発生すると、プログラムカウンタの値を、割り込みベクタに登録してある割り込みハンドラへのアドレスに書き換える。
このとき、もとのプログラムカウンタの値は自動的にスタックや専用レジスタに保存される。(保存先はCPUによってことなる。)同時に、モード・レジスタの値も保存され、自動的にモード・レジスタの設定は割り込み禁止に変更される。
割り込みハンドラの最後では、プログラム・カウンタとモード・レジスタの状態を復帰させる処理を行う。

H8の仕様

CCR

H8では、モード・レジスタの機能をもつCCRというレジスタがある。CCRはモード・レジスタの役割の他にも、フラグ・レジスタの役割も担っており、各桁のビットがそれぞれの役割を果たしている。

PCとCCRの保存先

割り込みが発生した時の、プログラム・カウンタとCCRの保存先は、スタック・ポインタ(PC)のER7レジスタになる。ER7の指す先のアドレスの上位1バイトにCCR、下位3バイトにPCの値が格納される。

割り込み復帰方法

プログラム・カウンタとCCRの値を復旧させるrte命令を、割り込みハンドラの最後で呼び出す。

インライン・アセンブラ

C援護のプログラムの中で、アセンブラを記述るためのもの。
今回は、ブートローダのプログラム中でCCRを操作するために使用する。


12ステップで作る組込みOS自作入門

12ステップで作る組込みOS自作入門

組み込みOS(第6回)

ステップ6の内容

前回ステップで、転送したELF形式ファイルを解析し、セグメント情報を読み取り、とりあえず内容を表示することだけはできた。今回のステップでは、読み取った情報をもとに、ファイル内容ををRAM上にコピーし、エントリーポイントに処理を渡すプログラムを実装する。

エントリ・ポイント

実行を開始するアドレスのこと。ELFヘッダの中には、エントリ・ポイントを保持するために割り当てられた領域がある。

関数へのポインタ

ELF形式ファイルから読み取ったエントリポイントのアドレスは、関数へのポインタとして変数に持っておく。関数へのポインタ f は次のように宣言できるらしい。

[返り値の型] (*f)( [引数] );

コード中に次のように書くと、f にポインタが渡されている関数が呼び出される。

f([引数]);

疑問点

runコマンドの動作

ブート・ローダのrunコマンドは、1回目は必ず失敗する。2回目はうまくいく。
理由はわからなかった。
アドレスを表示させてみたところ、一度目のコマンド実行時は、エントリーポイントのアドレスが0になっているが、2度目は正常にアドレスが入っている。しかし、1回目と2回目のコマンド実行の間に何か処理が入っているわけではないので、原因がわからない。

OS側のmain関数

OSのコマンド”exit”で、os側のmain関数はreturn されるが、その後の処理がどこに渡されるかがわからない。書籍のままのコードだとexitにあとフリーズする。これはおそらくリンカ・スクリプトの無限ループのため、この部分を丸々削除するとブート・ローダに処理が戻るはずだと考えた。しかし実際は、1回目のexitコマンドでは再びOSが起動し、2回目はブート・ローダに処理が戻った。原因が特定できなかった。


12ステップで作る組込みOS自作入門

12ステップで作る組込みOS自作入門

組み込みOS(第5回)

ステップ5の内容

ステップ4までで、とりあえずファイルの転送まではできるようになった。ここからは、転送したELF形式ファイルをRAM上に展開できるようにする。ステップ5では、展開はせず、ELFの解析プログラムまでを作成する。

マジック・ナンバ

ELF形式ファイルの先頭にある16バイトの領域に配置されている数値データのこと。様々な識別情報が書かれており、特に最初の4バイトは、「0x7f 0x45 0x4c 0x46」となっていて、これによってELF形式であることが判別できる。

「セクションと」と「セグメント」

セクション

リンカが、複数のオブジェクト・ファイルをリンクして一つの実行形式ファイルにする際に使用する。それぞれのオブジェクト・ファイルのセクションに従って、同じ種類のデータは、実行形式ファイルにおいて、同じデータ領域(.textとか)にまとめられる。

セグメント

ローダは、実行形式ファイルの内容を、書かれているセグメント情報にしたがって、セグメント単位でメモリ上に展開する。

疑問点

リンカについて

リンカ・スクリプト(ld.scr)は、リンカそのものではなく、リンカへの指示が書かれたファイルであることを理解できた。しかし、そうなるとリンカ本体はどれになるのかまだ理解できてない。


12ステップで作る組込みOS自作入門

12ステップで作る組込みOS自作入門

組み込みOS(第4回)

ステップ4の内容

今までは、プログラムの書き換えのたびに直接ROMを書き換えてきたが、ROMの書き換え回数には上限があるため、この方法を変更する。ROMにはブート・ローダーを書き込んでおき、起動のたびに、シリアル経由でプログラムをダウンロードし、RAMに展開する。この方法なら、ブート・トーダーを完成させてしまえば、プログラム本体を修正するたびにROMの書き換えを行わなくてすむ。
今回は、XMODEMプロトコルによって、ファイルを転送するところまでやる。

XMODEM

シリアル経由でのファイル転送プロトコル。古くからある(パソコン通信時代に流行ったらしい。)
プロトコルの実装」という響きのワクワク感。

シリアル受信用のライブラリ

今後はH8側でも受信を行うので、そのためのライブラリを実装する。

エコーバック

シリアル通信を行うときのエコーバックはどこに書かれているんだろうかという疑問は以前から持っていた。シリアルドライバで行ってしまうこともあるらしいが、今回、ドライバは送受信に専念するという意味でライブラリの中に書いた。

ファイル転送手順

kz_xmodemを使う方法

書籍で標準で使われている転送ツールではなく、kz_xmodemを使用すると、操作手順が少なくて楽。
(参考サイト: http://blog.livedoor.jp/noanoa07/archives/1994090.html

$ kz_xmodem [送りたいファイル名] /dev/tty.usbserial-FT0UMQ8C

(その後普通に通信)

$ sudo cu -l /dev/tty.usbserial-FT0UMQ8C
書籍通りやる方法(macの場合)

多少操作が増えても、せっかく実装したloadコマンドを使いたい場合は次のようにする。

kzload> load
$ ~+ lsx [送りたいファイル名]

(あとは待つだけ)

ABI(Application Binary Interface)

スタックポインタには、レジスタER7が使われている。だから、ジャンプ命令jrsやリターン命令rtsでは、引数を指定しなくても、勝手にER7が使われている。これはコンパイラが自動で行っているが、多くの場合、ABI(Application Binary Interface)という規格でCPUごとに決められている。したがって、CPUのABIをサポートしているなら、違うコンパイラコンパイルしたオブジェクトファイルでもリンクして正常に動作することができる。

スタートアップの無限ループ

スタートアップ(starup.s)の最後にある

1:
	bra 1b

このbraは戻り先を覚えない簡易的なジャンプ命令のようなもの。引数の1bは、「この命令より前にある”1:”というラベルの内最も近いもの」という意味である。つまり、直前にそのラベルがあるので、無限ループを表す。これ以前のスタックmain()へのジャンプの後、つまりmain()から戻ってきたとき、おかしな動作をして暴走しないようにする対策になっている。

疑問点

ファイル転送のに関して

lsxと、実装したXMODEMに関するプログラムの役割の範囲がよくわからない。
lsxはひたすらプロトコルのルール通りにビットデータを投げてきて、実装したプログラムは、それを意味のある形で上手く受け取っている?
さらに、kz_xmodemを使用した場合は、実装部分に関しては丸々使わないことになるのでは・・・と思っているけど、その認識はあっているのだろうか。 

ABIに関して

対象CPUのためにどのABIを使うのかというコンパイラの設定は、どこでやっているのかがわからない。Makefileの項目のどれかがその設定なんだろうか。


12ステップで作る組込みOS自作入門

12ステップで作る組込みOS自作入門

組み込みOS(第3回)

ステップ3の内容

ステップ2まではできなかった静的変数の書き換えを可能にするため、各ファイルを修正する。

変数の種類

変数にには「静的変数」と「自動変数」という種類がある。これらは、プログラムで宣言された位置によって種類が決まり、割り当てられるメモリ領域も異なる。

静的変数

関数の外で宣言される。初期値がないものはROMのデータ領域に置かれ、あるものはROMのBSS領域に置かれる。

自動変数

関数の内側で宣言される。RAM上に置かれる。

静的変数の書き換え対応

静的変数は、ROMに置かれるが、これだと内容の変更ができないので変数として使用できない。この対策として、マイコンの電源を入れた直後、ROMのデータ領域の内容を、RAMにコピーして、プログラムの変数からはそのコピー先にアクセスするように設定した。コピーはmain.cの最初で行い、設定はリンカ・スクリプトで行う。このような一連の処理を、「
VA≠PAにする」というらしい。

PA(ロード・アドレス/物理アドレス

静的変数の初期値が配置されるアドレス

VA(リンク・アドレス/仮想アドレス)

プログラムから静的変数を使うときにアクセスするアドレス

ELF形式

コンパイラが生成する実行形式ファイルのフォーマット。linuxにおいては、readelfコマンドで解析することができ、メモリのセクション情報や、各シンボルが割り当てられている番地などが確認できる。初期値のない静的変数が、BSS領域に置かれている事などもここで確認する事ができる。
(本の環境と異なる部分)
macでは、readdlfコマンドが使えないので、インストールする必要があった。

% brew install binutils

使用するときは、readelfではなく、greadeflとする。

% greadelf -a kzload.elf

その他

疑問が2つほど残った

  • リンクとは、プログラム中の関数や変数などのシンボルに対して、メモリを割り当ててやる作業という認識あっているのか?
  • リンカの実体は、リンカスクリプトなのか?


12ステップまで、3月中にやりきりたい。なんとしても時間を作り出して確保する。


12ステップで作る組込みOS自作入門

12ステップで作る組込みOS自作入門

組み込みOS(第2回)

 ステップ2の内容は、シリアルコントローラのレジスタによる設定、標準ライブラリ風関数の実装が主な内容だった。今回気になったのは「分周」と「ボーレート」の関係くらい。
 
 まず分周とは、CPUのクロック周波数をnで割ってほしい周波数を作ることらしい(n:分周比)。そして、この作った周波数をシリアルモジュールに供給する。
メインクロックを分周するnをBRRに設定すると思っていたんだけど違うらしい。どうもBRRの値とボーレートの対応表がマニュアルにマイコンごとに用意されていて、それを見て設定すれば良いらしい。
 マニュアルを見ると、表の他にBBR値の計算式も書かれていた。確かに歩調同期方式の式でBBRは64になる。ただし、(64*2^(2n-1))と−1の部分の意味がわからない。64*2^(2n-1))は設定するシリアル通信で使うビット長とかで違うのかもしれない。ビット長8なら8になるとかだったら理解できる。
 クロック同期方式と歩調同期方式の違いもよくわからなかった。この辺も確かに理解したい部分ではあるんだけど、この辺にかかりっきりになってしまうと進まない。この本で一番やりたいのは、メモリ管理とかスレッドの部分なので、あまりここで時間は使わないようにしたい。少し調べて、その時理解できなくても、「具体的にどこが」わからないかを記録しておけば(数学ガール的にいうと「分からないの最前線」)、最低限またあとで考えることができるからよしとしたい。


(蛇足)
 第1回の記事からだいぶ間が空いてしまった。期末試験その他いろいろあったが、時間を作れなかったわけではないので結局いいわけ。とにかく、本を進める過程で書き残し続けることはやめたくないので、今回はかなり雑な文章になってしまったが形に残すことを優先した。時間があれば書き直したい。


12ステップで作る組込みOS自作入門

12ステップで作る組込みOS自作入門

組み込みOS(第1回)

『12ステップで作る組み込みOS自作入門』という本を購入した。


以前から気になってはいたが、なかなか手を出さずにいたら存在を忘れてしまっていた。
再び購入意欲が高まった理由は、今期の大学のOSに関する講義があったこと、そしてバイト先(組み込み系の会社)に置いてあるのを見かけて思い出したから。
また、自分の中で不足しているかつ、欲しい知識として、アプリケーション層未満の階層での知識がある。
これは単純に自分の興味がそそられる部分でもあるし、将来的にもその方向で進んで行きたいという思いが最近大きくなっているからだ。
(あとこの動画を見たのも結構大きい。本当に楽しそうに話すので感動した。)


このような直接何かを作り出さない活動に、今のタイミングで時間を使うはどうかという考えが無いわけではないけど(「もっと実践的にカタチのあるものを作ってやりながら学び、実績を作るほうがいいかもしれない・・・」等)、「知りたい!やりたい!」と直感的に思えたタイミングでやるのが、経験的に一番吸収が良いので今すぐやる。
12ステップ、約500ページで少ない量ではないが、最後までさっさとやり遂げてしまいたいと思う。


ここから本題。
今回は初めてなのでステップ1の環境構築をやる。
現在まともに使えるPCがMacBookPro (Retina 13-inch、Early 2015)しかないのでこれを使う。
環境を作る手順は以下のサイトを参考にさせてもらった。
blog.livedoor.jp
書籍ではmacに関することは書かれていないので非常にありがたかった。


購入したケーブル等はすべて同じものを購入して問題なく使えた。
手順もほぼ同じように進めることができた。
ただし、ブログを書かれた方と使用しているgccの種類と設定等が違うようで、ブログには書かれていないエラーが発生したので少し言及する。


binutilsをビルドするとき

clang: error: unsupported option ‘-print-multi-os-directory'

という表示がされた。
調べてみたところ、このオプション‘-print-multi-os-directory'はコンパイル完了後に設定などをただ表示してくれるだけの機能なので、とりあえず無視したが、結果的に今のところは問題ない。
macgccLLVMでホントのgccじゃない(?)から云々・・・みたいなことが関係していそうだが、進めることを優先したいのでまた今度考えることにする。


以上、トラブルはこの程度で思っていいたよりもスムーズに、ステップ1は終わった。
新しく知ったことは、このブログに書くことを目標にこれから進めて行きたい。



12ステップで作る組込みOS自作入門

12ステップで作る組込みOS自作入門