Tag Archives: 開発日誌

2009-04-12

  • L4_Mutexが失敗する。

2009-04-11

  • 割り込みを有功にした。
    • SH7780では割り込みのマスクを解除するだけでなく、割り込みの優先度を2以上にしなければならなかった。
  • Pckは50MHz。ティックは10ms。Pck/4のタイマーで10msを測るには?
  • TMUの割り込み要因がクリアされていない。
    • TMU_TCRのUNFをクリアしなければならない。
  • キャッシュをフラッシュする区間を割り込み禁止にしていたのだが、これはその区間外が割り込み許可であることが前提。ところが、実際には、まわりの区間は 割り込み許可である。キャッシュをフラッシュした後も割り込み禁止でなければならないのだが、割り込みを許可してしまっていた。
  • カーネルモードでの割り込みの処理に間違いがあった。
  • 以上、Rev.125
  • 結果、KTESTが最後まで走るようになった!

2009-04-10

  • CACHE0600で落ちる。
    • キャッシュをフラッシュする際にアドレスが有効かどうか調べる機能をONにする。
  • CACHE0600の状況を修正する過程でページフォルトが処理されない問題が発生。
    • UTCB参照アドレスのキャッシュが更新されていない。
      • (ワークアラウンド) UTCB参照アドレスのUTLBエントリをライトスルーにすることでなんとなく動いているが…Rev.120
      • 大量に出ていたinvalid page faultも嘘のように消えてしまった。
      • UTCB参照アドレスをキャッシング不可にした。
  • TODO UTCB参照ページをキャッシュするかどうかについては、調査が必要。
  • L4_NotifyがエラーでかえってくるIPC3400
    • システムコールを修正。Rev.121
  • KMEM02でUTCBの上限値を設定。Rev.122
  • L4_Yieldでブロックする。
    • どうやらタイマーが有功になっていないみたいだ。

2009-04-09

  • IPCがうまく行っていない。
    • スレッド1がスレッド2を生成し、スレッド2にBlock Sendする。スレッド2はまだ走っていないので、このBlock Sendは一旦スケジューリングキューに登録される。スレッド2はページャと通信し、メモリページを取得する。スレッド2はスレッド1からのメッセージを 受信する。
    • 最後のスレッド2がスレッド1からのメッセージを受信するところが、受信されていない。
    • スレッド1からスレッド2へのIPCはコンティニュエーションを使って復帰される。(restart_ipc)
    • restart_ipcはSYS_IPC_RESTART(アーキテクチャ依存コード)を呼び出す。SYS_IPC_RESTARTはcall_with_asm_continuation(アーキテクチャ依存コード)を呼び出す。
    • call_with_asm_continuationが正しく状態を復帰していなかった。
      • この関数を実装した当初は、continuationを呼び出すものだと思っていたので、continuationにジャンプしていたが、これは間違い。
      • 正しくは、continuationをPRレジスタに格納し、functionを呼び出さなければならない。Rev.116
  • 新しくアドレス空間を生成した時にkmem_resourceが確保されていないようだ。
    • kmem_resourceはどのタイミングで確保されるのか?
    • この場合には、そもそもkmem_resourceを使ってはいけない。kmem_resourceはUTCB参照ページを参照するページテーブルエント リの確保に使われている。つまり、このページテーブルエントリを作成するのが間違いということになる。幸いなことに、UTCB参照ページを共有ページにす ればページテーブルエントリの確保は必要なくなる。ただし、以下の条件を満たす必要がある。
      • UTCB参照ページはTLBから追い出されない。
      • UTCB参照ページのエントリはTLBの中で最大一つ。
    • 直した。Rev.119
  • キャッシュテストで落ちる。

2009-04-08

  • ページフォルト(TLB例外)後、ページフォルトハンドラが例外アドレスをマッピングする。この操作はアドレスをページテーブルに登録するだけで、TLB に登録するわけではない。したがって、ページフォルトを発生したスレッドに一旦処理は戻り、再び、TLB例外を発生させ、TLBをフィルするという流れに なっていた。
    • ページテーブル登録後にTLBをフィルするように変更。Rev.113
  • (ワークアラウンド) ipc_handler内でTLBにないUTCBアドレスにアクセスする可能性がある。UTCBアドレスはP0領域の仮想アドレスなのでTLB例外を発生 させる。現在の実装では、ipc_handlerは割り込み禁止区間に設定されている。そのため、TLBにないUTCBアドレスにアクセスすると処理が進 まなくなり、クラッシュする。
    • (方法1)割り込み禁止区間を撤廃する
      • TLB例外以外の優先度の高い例外や割り込みが発生する可能性がある。
        • データTLB例外の優先順位は6番め。
    • (方法2)物理アドレスでUTCBにアクセスする。
      • TCB経由でUTCBの物理アドレスを得られる。
    • とりあえず方法1を試す。動作はするが、最終的にはエラーが出てKDBに落ちる。
      • kernel access raised user page fault (space.cc l212)
    • ここから得られる結論は、そもそもカーネルモードでUTCBに対するTLB例外を発生させてはならないということである。
    • 方法2でうまくいった。

2009-04-07

  • ページテーブルエントリが思ったように更新されていない。
    • ページテーブルエントリのバグ(pgent_t::clear)
  • get_current_kmem_resourceが失敗する。アサーションに引っかかる line 149 @ kmem_resource.cc。
    • generic_space_t::activate内でUTCB参照ページのマッピングを常に新しく作成していたため、メモリリークしていた。
  • ipc_syscall_return内でUTCBにアクセスするとき、ページフォルトが発生する場合がある。この場合に対処していなかったため、クラッシュしていた。

2009-04-06

  • (ワークアラウンド) データキャッシュにもTLBにも存在しないエントリをライトバック(OCBP)しようとして、クラッシュしている。Rev.108
    • ページテーブルに登録されているが、TLBに登録されていない場合には次の二つが考えられる。
      1. マッピングしたがそのアドレスにアクセスしていない。
      2. マッピング後アクセスし一旦はTLBに登録されたが、追い出された。
    • 2.の場合はデータはキャッシュされるのでOCBP命令は成功する。

2009-04-02

  • ktestがアボートされる。
    • irqのリストが取れないのが原因。ElfWeaverがNO_DEVICE_IRQ_LISTという構造体をアロケーションするのだが、どのような仕組みでアロケーションするのかよくわからない。
    • とりあえずアサーションを無視。
  • ThreadControlでアサーションに引っかかる。
    • システムコールの引数の処理の間違いだった。
  • IPCでデッドロック
    • IPCの受信時に送信元を正しく返していなかった。Rev.101
  • KDBのスタック管理にバグがあった。修正。Rev.99
  • KDB呼び出しのレジスタ管理にバグがあった。修正。Rev.100
  • IPCのメッセージが配送されない。
    • KDB呼び出しがレジスタを破壊していた。Rev.105

2009-04-01

  • IPCがおかしい。ブロックしない。
    • UTCBをカーネルが読み取れていない。L4_WaitはフラグをセットしL4_Ipcを呼び出す。このフラグがセットされることでIPCはブロックする 仕組みになっている。このフラグはMsgTagにセットされ、UTCBに保存される。カーネルはUTCBからこのフラグを読み出す。カーネルがブロックし ないということは、このフラグを正しく読み出せていないことを意味する。
    • IPCの実装が未完成だった。Rev.93
  • UTCBでTLB多重ヒット例外が出る。
    • generic_space_t::activate内
    • UTCBを参照するためのページは共有ページに設定されていたのだが、この設定ではASIDが比較されない。結果としてTLB多重ヒット例外を発生させていた。Rev.95
    • メモ:UTCB参照ページは共有にすることでUTLBを節約できる。

2009-03-31

  • ページテーブルエントリをフリーするときにフリーリスト(kmem_free_list)のアドレスが変(0×80000000)
    • kmem_free_listはkmem_tのメンバー。
    • kmem_tはkmem_resource_tのメンバーになる(heap)。
    • kmem_free_listは0番目のメンバーで、kmem_resource_tの中のkmem_tは0番目のメンバーなので、アドレス0×80000000はkmem_resource_tのアドレスになる。
    • つまり、kmem_resource_tの配置がおかしいことになる。
    • kmem_resource_tはget_current_kmem_resource()で取得する。
  • free_utcb_area_memory()がフリーリストを書き換えてしまう。
  • utcbのアドレスに対応するpgentの持つ物理アドレス(utcbの物理アドレス)が0になっている。これが原因でfree_utcb_area_memoryがおかしな挙動をする。原因はUTCBのアロケーションの失敗か?
  • 結局のところ、ページテーブルエントリの有効・無効の判断の仕方に間違いがあったということが分かった。疑わしきは自分の書いたコードである。Rev.92

2009-03-30

  • SpaceControlがちゃんと動かない。

2009-03-27

  • トラップハンドラの見直し終わり。ユーザーコンテキストをTCBに保存するようにした。Rev.83
    • KDBが使えるようになった。
  • Hello, world! Rev.85
  • KTESTを走らせてみる。SPACE_CONTROLでこける。コンティニュエーションのアドレスがおかしい。

2009-03-26

  • トラップハンドラを見直し中。コンテキストの退避と復帰、再突入の考慮など。
  • メモ
    • ユーザーモードからカーネルモードに入る(システムコール、例外、割り込み)
      • ユーザーコンテキストをユーザースタックに退避
      • カーネルスタックに切り替え
      • システムコール、例外、割り込みの処理
      • カーネルの特定の場所でプリエンプション可能になる
      • 例外、割り込みの発生
      • カーネルコンテキストは破棄する
      • カーネルスタックをリセット
      • 例外、割り込みの処理
      • 終了後、コンティニュエーションを実行。TCBからレジスタを復帰。スタックはリセット。
      • 終了後、コンティニュエーションを実行。TCBからレジスタを復帰

2009-03-25

  • ユーザープログラムがこけるのも当たり前、ルートタスク用のcrt0がちゃんと実装されていなかった。
  • おそらくHelloWorldは実行されているが、メッセージが表示されない。シリアルドライバが不完全か?
    • KDBコール(システムコールの一種)がおかしいので、シリアルドライバをデバッグできない。まずはKDBコールを直さなければ。
      • 一般例外ハンドラの配置が違ってたので修正。
      • KDBコールは正しいようだ。
      • 部分的に未実装なので、実装を完璧にする必要がある。
  • read_write_lockのアサーションに引っかかる。一時的なエラーだったみたい。
  • ユーザーレベルのシリアルデバイスドライバがおかしい。

2009-03-24

  • EXPEVTが0の問題は、とりあえず、0を読み込み例外(本来は0×40)と判断することにした。
  • ElfWeaverのスタックポインタの計算が間違っている?
DEFAULT_STACK_SIZE = 0x1000

def get_sp():
    virt_addr = self.stack.virt_addr
    size = self.stack.size
    return virt_addr + size

となっているけど、これではスタックポインタが次のページに行ってしまう。

def get_sp():
    virt_addr = self.stack.virt_addr
    size = self.stack.size - 4
    return virt_addr + size

とすべきだろう。

  • pgent_t::is_readableの判定が間違っていたので修正。
  • 正体不明のページフォルト(0×00117550)が発生する。
    • 正体不明ではなく、期待通りのページフォルト。しかし、カーネルが正しく処理できていない。
    • make_subtreeで64kページを考慮していないのが原因だった。修正。
  • ユーザーコンテキストが元に戻らない。例外発生前のコンテキストが例外処理後に復元されない。
    • tcb_tの中のktcb_tにユーザーコンテキストを保存。回復にはexception_returnを新たに実装。
    • 8ビットイミディエイトの加算演算にはまる。結果が8ビットを越えてもキャリーしない。つまり、
      • 0×88301C60 + 0xA4 = 0×88301C04となる。
      • 上記の式の正しい答えは0×88301D04
    • この様な場合にはイミディエイトではなくレジスタに一旦値をロードして計算する。
  • ユーザープログラムがアサートでこける。OKL4_ENV_HEAER_MAGICが取れていない。

2009-03-23

  • TCBは空っぽではなかった。しかし、PCが指すアドレス(0×100000)には何も配置されていない。
      HelloWorldが期待通りにマッピングされていないのが原因のようだ。map_regionを見直す。
  • TLBミスハンドラがオフセット0×400にない!
  • クラッシュの原因はTLBミスハンドラにあるようだ。
    • TLBミスハンドラの冒頭でユーザーコンテキストをユーザースタックに退避する。しかしながら、ユーザースタックはTLBにエントリがない。これが原因でダブルフォルトが発生し、カーネルがリセットされる。
    • generic_space_t::activate内でユーザースタックをTLBエントリに追加した。
  • TLBミスハンドラで例外コードがとれない。EXPEVTを読み込むと値が0。

2009-03-19

  • ページマッピングがうまくいかない。カーネルモードでP0領域にアクセスしようとしてこける。UTLBはちゃんとセットしているんだが。。。
    • 読み込みは成功しているようだが、書き込みはダメだ。
    • ライトバックのページを複数箇所にマッピングする時はキャッシュをフラッシュする必要がある。
    • 下記のページテーブルの構成に付随した問題だった。ページサイズを直接指定することで取り合えず解決。
  • ページテーブルの構成はTODO
    • add_mappingで指定したページサイズとlookup_mappingで取れるページサイズが違う。ページテーブルの構成がコアの実装と合っていないようだ。
    • 直した。
  • initial_to_userでTCBが空っぽ。なのでリセットされてしまう。TCBをどこかでセットアップしているはずなんだが…

2009-03-18

  • ページマッピングでパニック。ページサイズが0になっている。アドレスが0×117400となっており、1kアラインである。これはおかしい。設定ファイル(machines.py)で1kページを許可しないようにしたら直った。本質的な解決ではないかもしれない。
  • パニックするようなエラーはでなくなった。ちゃんと動いている?HelloWorldが使うシリアルポートドライバがまだ出来ていないので確認できない。
  • シリアルポートデバイスドライバを実装。でもメッセージは出ない。どこかでハングしているようだ。
    • それもそのはず。switch_toが未実装でコンテキストスイッチが起きていなかった。
  • switch_to実装も新たなバグ。UTCBの実装を見直さなければならない。

2009-03-17

  • キャッシュのコードを修正。オペランドキャッシュのフラッシュのためにVIRT_RAM_BASE(0×88210000)を使っていたのだが、実はこの アドレスにはグローバル変数が格納されおり、このグローバル変数の変更がライトバックされていない状態でキャッシュをフラッシュしようとすると、今のアル ゴリズムではグローバル変数が破壊されてしまう。VIRT_RAM_BASEを止めて、KERNEL_AREA_START(0×80000000)に変 更。
    • 0×88000000とすべきか?
  • トレースを表示するように変更。コマンドラインで指定する方法を探すのに手間取った。カーネルソースでは、VERBOSE_INITというディレクティブ でトレースの表示をコントロールしている。これを単にコマンドラインでVERBOSE_INIT=trueとすれば、トレースの表示が有効になる。他の ディレクティブも同様と思われる。
  • small_alloc_t::allocateのメモリテストでエラー。check_poisoned_areaで引っかかる。メモリが汚染されているらしい。
    • 他の誰かが使っている
    • オーバーフロー
    • キャッシュ操作の間違い
void *
small_alloc_t::allocate(bool zeroed)
{
    ...
    if (!first_free) {
        /* ここでは4Kのブロックを確保 */
        first_free = allocate_block(mem_group);
        if (!first_free) {
            return NULL;
        }
        /* 確保したブロックを汚染しておく */
        poison_area(get_object(first_free, 0), objs_per_block * obj_size, KMEM_POISON_FREE);
    }

    /* ファーストフィットでフリーブロックを確保 */
    int position = bitmap_findfirstset(first_free->get_bitmap(), objs_per_block);
    void* object = get_object(first_free, position);
    bitmap_clear(first_free->get_bitmap(), position);

    /* 現在のブロックがすべて使われているならば、first_freeをアップデート */
    while (bitmap_findfirstset(first_free->get_bitmap(), objs_per_block) == -1) {
        first_free = first_free->next;
        if (!first_free) {
            break;
        }
    }
    num++;

    check_poisoned_area(object, obj_size, KMEM_POISON_FREE, object);
    ...
}
void
poison_area(void* addr, word_t size, unsigned char poison_value)
{
    memset(addr, poison_value, size);
}
void
check_poisoned_area(void* addr, word_t size, unsigned char poison_value, void* obj_addr)
{
    unsigned char* p = (unsigned char*)addr;
    while (size--) {
        if (*p != poison_value) {
            enter_kdebug("poison");
        }
        ++p;
    }
}
  • 原因はmsbを実装していないことにあった。
  • l1_entry_tとl2_entry_tのサイズがおかしくなっていたせいで、メモリアロケーションがおかしなことになっていた。
    • l1_entry_tとl2_entry_tは4バイトでなければならないのだが、ビット指定を間違えていて33ビットのデータ構造になってしまっていた。

2009-03-16:カーネルが動き始める

  • MMUCRなどを更新した際に、任意のアドレスでICBIを発行するのだが、その任意のアドレスを0×1000とするとクラッシュする。
    • 0×80000000として回避した。
  • 最初のカーネルメッセージが表示された!
  OKL4 - (provider: Open Kernel Labs) built on Mar 16 2009 14:50:15 using gcc version 3.4.5.
  • run_init_scriptでこける
    • phys_to_virtのバグ。Machine.pyを修正。
    • Elf Weaverが物理アドレスでinit scriptを書き込んでいる一方で、カーネルは仮想アドレスでそのスクリプトをロードする。

2009-03-13

  • いよいよ実機で走らせつつ、デバッグを開始する。
    • まずはデバッガ用のウィンドウズのインストールから。

2009-03-12:ビルドが通るようになる

  • ldスクリプトのしょうもないバグを修正。ビルドが大分進む用になった。
  • crt0_rootserver.sppを実装したら、ビルドが通った

2009-03-11

  • とりあえずカーネル内の空の関数は実装した。
  • ライブラリの実装に取りかかる。
    • KDBインターフェースのテンプレートを作成
    • 実装完了か?
  • シリアルデバイスドライバがないのでビルドが停止する。

2009-03-10

  • トラップハンドラ実装の続き。
  • 例外ハンドラの実装。
  • KDBインターフェースを実装しなければならない。lib/l4/include/syscall_asm.hにKDB用のシステムコール番号だけは予約した。

2009-03-09

  • トラップハンドラを大幅に変更。例外コードをオフセットにして各ベクタに飛ぶようにした。
  • コンティニュエーションの仕組みと役割を理解した。

2009-03-06

  • レジスタのネーミングを仕様書どおりにする。いままでは可読性を高めようと独自に名前を変更していたが、かえって仕様書との読み替えが面倒になるのではないかと考えた。その代わり、コメントで可読性を補うことにする。

2009-03-05

  • 割り込みがいやらしい。L4ではSHでいうところの外部割り込みしか想定していないようだ。内部割り込みもユーザ側に投げる必要があると思うので、その場 合、内部・外部割り込みを一つの空間で管理しなければならないが、各割り込みは必ずしも連番になっていない。一方でL4内部では配列で割り込みの管理をし ている。割り込みの番号空間を連番空間にマッピングする関数が必要なのだが。。。
  • 結局、虫食いになってもいいから、大きめの配列を用意することにした。将来的に今穴の開いている割り込み番号に何かが加わるかもしれないし。