きらーえるふ の個人ページっぽいもの

自己紹介

今就活中なので実際に作るかどうかを決めるのは当分先になりますが、面白そうな話題なので読み進めています。更新停止中の本家については、適当に検索すれば出てくると思います(笑)。

読書記録

単に進行状況をメモ書き程度に残しているだけです。つい先ほど読み終わりました。分からない点に関しては自力でそれなりに調べて見て、それでも残っているようなら、q_and_a コーナーに投稿してみようと思っています。

初めはOSなんか本当に理解出来るのか心配でしたが、上手い具合にかみ砕いて説明しているので、とても分かりやすくまとまっているように感じています。全体的に前の章でやったことのやり直しが少ないと感じているので、最初にOS本体を完成させた後に本文を書き始めたのでしょうか。OSの機能を練る段階でかなりの時間を費やしていると思うと、この本の有り難みが感じ取れます。

最終日(p.694,695)に書かれていた筆者の目指していることについてですが、本文中からも十分に伝わってきました。最後までたどり着いて始めて分かる筆者の意図に、正直驚きを隠せませんでした。ちなみに、アクセス競合の話についてですが、私のような人へのメッセージが書かれていたので、一通り検証が済み次第報告する予定です。

Chapter 00 - 07

  • p.27 ファイルの先頭にあるバイト=0バイト目として書かれているようです。
  • p.37 ビッグエンディアンのCPUは、リトルエンディアンとは逆の格納順序になりますね。
  • p.78 アセンブラから入ってるので、このポインタの説明は上手いと思いました。
  • p.117 signed int をシフトしているので算術シフトになりますが、ここでは AND 演算をしているので、実質論理シフトとの差はありませんね。
  • p.154 割り込みの解除順番(スレーブ→マスター)についてですが、この順番になる理由が分かりませんでした。スレーブの割り込みを解除してから、マスターの割り込みを解除するまでの間に、スレーブに割り込み信号が入ったらどうなるんだろう、と初心者なりの妄想しています。でも、割り込み処理中の割り込みをどう扱うかすら分かっていないので、この発想自体が正しいかどうかは不明です…。

Chapter 08 - 14

  • p.166 ここまでの所を何度も読み直して、ようやく asmhead.nas にある [JMP DWORD 2*8:0x0000001b] の意味が分かりました。今まで bootpack.hrb は、[ORG 0x00280000<読み込まれるアドレス>] 相当のコマンドを用いて生成していると勘違いしていました。実際の所は、GDT[2].base = 0x00280000 なので、bootpack.hrb は [ORG 0x00] 相当のコマンドを利用して生成しているんですね!他にも asmhead.nas の一番最後に付けたラベルを bootpack.hrb が格納されているアドレスの目印として用いたりなど、多くの驚きがありました。何の道しるべも無しに32bitCPUを使いこなすのは難し過ぎると感じましたが、制作を幾つかのステップに分けて進めてくれているお陰で、とても分かりやすい内容になっていると思います。
  • p.180 volatile という単語ですが、この場合初心者の為に使用を見送ったのかな、と思いました。
  • p.225 sheet_updown 内部の最初の sheet_refresh ですが、[height + 1] は [height] のようが気がします。
  • p.228 sheet->buf の初期化が必要なように思いましたが、 sheet[0] が画面全体を覆っているので不要ですね。このようなことばかりに目がいくのは、日々C言語で「初期化をやるように」と考えているからなのでしょうか。
  • p.246 このページ以降、使用中のタイマーに対して timer_settime を呼び出すと、同じタイマーが2つ登録されてしまうようです。

Chapter 15 - 21

  • p.298 タイマー関連のマルチタスク対応について考えて見ましたが、書き込むFIFOを変えることで対処しているようです。タスクAの実行中にタスクBで設定された割り込みが入った場合でも、(タスクAではなく)タスクBのFIFOにその情報を書き込むようにすれば、セマフォ関連の操作は不要になるんですね。発想の転換に驚きました。
  • p.299 DWORD の前半2バイトを WORD として扱っていますが、これはリトルエンディアンならではですね。
  • p.319 逆に task_sleep 処理によってタスクが切り替わった場合、切り替わった先のタスクで io_sti() を呼ばないと、それ以降タイマーの割り込みが起こらない気がします。これも素人考えですが。一晩考えてようやく分かりました。タスクスイッチ時にIF(割り込み許可フラグ)も、スイッチ先のタスクのものに入れ替わるんですね。コメントの部分にある /* IF = xx */ と言うのが、割り込みフラグを表しているようです。
  • p.332 タスク動作中の task_run ですが、task->level[level]->now の書き換えは必要でしょうか。
  • p.345 fifo32_put(&task_cons->fifo, ...); に関してですが、この関数はスレッドセーフなので安全ですねスレッドセーフではない可能性があります。今になって気づきましたが、memman_alloc, memman_free の方はスレッドセーフになってないと思うので、前後に io_cli(), io_sti(), (+ io_getif()? ) を加えた方がよさそうな感じです。[int interrupt_flag = io_getif(); if(interrupt_flag) io_cli(); <処理>; if(interrupt_flag) io_sti();]
  • p.392 初アプリのセンスに爆笑しました。さすがです。
  • p.410 割り込み処理中の割り込みは禁止に設定していたんですね。なるほど。
  • p.412 for(i = 0; i < 8; i++) の条件が気になったので調べてみましたが、file_search() でピリオドが2つ以上含まれている場合のエラー判定が抜けているようです。file_search("hello.a.hrb", ...) は file_search("hello.hrb", ...) と同じ結果になります。
  • p.428 0x00102600 : ディスクキャッシュにある最初のファイル名の0バイト目のアドレスです。 &( (struct FILEINFO *)(ADR_DISKIMG + 0x002600) )->name[0]
  • p.429 この辺りの高度な話題についていけませんでした。とりあえず分かるところ以外流し読み状態です。読み直したら何とか分かりました。CPU 設計者は悪人のことを良く考えているんですね。
  • p.438 OSからアプリをFAR CALL出来るようにすると、アプリにRETF命令を許可する必要が出てきます。RETFが出来るということは、FAR CALLも出来ることに等しい(p.438)ので、p.447にあるようなcraskに繋がる訳です。OSからアプリへのFAR CALLは(今の設定では)出来ないようになっている理由は、こんな所にあったんですね。現在までの説明では、セグメントの壁を越えられる安全な方法として、割り込み(アプリ->OS)、RETF(OS->アプリ)を用いています。

Chapter 22 - 28

  • p.458 この説明で bootpack.bim の stack:3136k の謎が解けました。0x00300000 - 0x0030FFFF をスタック領域として使用する、という意味です。haribote.rul でスタック領域の直後にデータ領域を置くように指定しているので、0x00310000がデータ領域の始まりとなります。また、asmhead.nas ではデータ領域をこのエリアにコピーしているようです。メモリマップ(p.171)に「スタックなど」と書かれていた箇所ですが、このように使われているとは驚きです。でもGDT の方でOS用のSSを指定していないので、スタックアンダーフローエラーが検出出来ないような気もしました。
  • p.471 hrb フォーマット(p.460)中のデータセグメントの大きさ(0x0000)には、malloc 用の予約サイズも含まれているんですね。
  • p.496 shtctl->map を利用すれば、効率的に処理出来るみたいです。
  • p.536 私の環境では再現しませんでした。環境により動作が異なる現象が頻繁に起きそうなので、その大変さが伝わって来ます。
  • p.555 送信中に割り込みが起きる可能性について書かれています。p.345へのコメントですが、先を急ぎすぎたようです。
  • p.571 ウィンドウが全く表示されていない状態(背景画像のみ)かどうかの判定が抜けてるようです。
  • p.574 アプリがDSを変更すると無条件に例外が出ると思いこんでいましたが、変更先がアプリ用のDSなら問題無いようです。crack7はこのことを悪用した例ですが、すぐに対策されていますね(笑)。
  • p.597 alloca が必要な理由ですが、スタックオーバーフローを検出する為です。OSの実装例として、スタック領域の終端(一番若いアドレス)にアクセス不可能なページ(レッドゾーン)を置き、そこへのアクセスをトラップするという方法があります。一度にページサイズ以上の領域をスタックに確保しようとすると、レッドゾーンにアクセスすること無くスタック領域をはみ出してしまい、他のスレッドが使用している領域を気づかずに上書きしてしまう可能性があります。(例:char buf[256*1024]; と宣言した後、bufの先頭1KBのみを利用する場合。bufの64KB-128KBの領域がレッドゾーンの時は、allocaを使用しないとトラップ出来ない。)

Chapter 29 - 31

  • p.680 筆者の方針が良く伝わって来ました。最後まで読んだ人へのお楽しみですね。

fifo32_put, fifo32_get とスレッドセーフ

スレッドセーフかどうかの判断は、以下のソースが共に単一のマシン語にコンパイルされることに依存すると思います。(ただし、タスクが3つ以上ある場合は、スレッドセーフにはなりません。最初に気づくべきだったと反省ちう。)

fifo32_put():
fifo->free--;
fifo32_get():
fifo->free++;

z_tools に付属のコンパイラで試してみたところ、次のマシン語が生成されました。

fifo32_put():
1. MOV EBX,DWORD [8+EBP] ; fifo
... ; 略
2. DEC DWORD [16+EBX]
fifo32_get():
3. MOV ECX,DWORD [8+EBP] ; ecx = fifo
4. MOV ESI,DWORD [16+ECX] ; esi = fifo->free
... ; 略
5. LEA EAX,DWORD [1+ESI]  ; eax = esi + 1
6. MOV DWORD [16+ECX],EAX ; fifo->free = eax

fifo32_put() の方はスレッドセーフな形になっていますが、 fifo32_get() の方はスレッドセーフではありません(4終了後〜6実行前の間にタスクスイッチが起き、別タスクで fifo32_put() が実行される可能性有り)。fifo32_get() 先頭でfifo->free を使用しているので、コンパイラは5.の状態になってもfifo->freeが以前のままだと仮定しているのだと思われます。試しに volatile を指定してみましたが、単一のマシン語にはコンパイルされず、逆に悪化したようにさえ思えます。

fifo32_put():
MOV EBX,DWORD [8+EBP]
... ; 略
MOV EAX,DWORD [16+EBX]
DEC EAX
MOV DWORD [16+EBX],EAX
fifo32_get():
MOV ECX,DWORD [8+EBP]
... ; 略
MOV EAX,DWORD [16+ECX]
INC EAX
MOV DWORD [16+ECX],EAX

コメントなどありましたらご自由にどうぞ

  • ようこそ!分からないことはまず自分で調べてみて、それから質問するということなので、まだできるだけ答えないようにします。それにしても読むのがお早いですねえ。そんなに急がなくてもいいですからね(笑)。プログラムに関する疑問は、是非プログラムを改造してみて実験してみたらいいと思います。論より証拠ですね。なんかメモを読んでいると僕よりもずっとかしこそうで、恐れ入ります・・・。 -- K 2006-03-04 (土) 22:44:49
  • コメントありがとうございます。C/C++は6年位触っているんですが、アセンブラに関しては入門書をちらっと眺めてみた程度です。応用的なことをやるのはこれが初めてなので、数々のトリックを知り感動しています。 -- killer_elf 2006-03-05 (日) 21:05:53
  • 読破おめでとうございます! -- K 2006-03-08 (水) 00:44:33
  • ボリューム満点で読み応えのある内容で、この本に出会えたことを嬉しく思います。ありがとうございました。 -- killer_elf 2006-03-10 (金) 00:57:34
  • お疲れさまでした。「この本に出会えたことを嬉しく思います。」こんなメッセージを見ると、関わった者として大変うれしく思います。就職活動中とのこと。がんばってください! -- hideyosi 2006-03-10 (金) 02:03:54
  • p.412のファイル名中のピリオドの問題について。実は当初はこの仕様で問題ないと勝手に思っていたのですが、今になってこの仕様はいろいろ不便だと気がつきました。バグとして修正したいと思います(bug0004)。ご指摘ありがとうございました。 -- K 2006-03-25 (土) 14:17:17
  • スレッド本の読書中にallocaが必要な理由を見つけたので更新。一見関係無さそうに見えても、実は糸のように繋がっていたとは想定外でした。 -- killer_elf 2006-04-11 (火) 21:41:09

コメントお名前NameLink

リロード   新規 編集 差分 添付   トップ 一覧 検索 最終更新 バックアップ   ヘルプ   最終更新のRSS
Last-modified: 2006-07-18 (火) 08:27:09 (4571d)