seL4のx86_64におけるブート処理を読んでみる

  • src/arch/x86/(32|64)/head.S@BEGIN_FUNC(_start)
  • src/arch/x86/kernel/boot_sys.c@boot_sys()
    • 第1引数 multiboot_magic に応じて try_boot_sys_mbi(1|2) のどちらかを呼ぶ
    • 第2引数 mbiMultiBoot Info かな
    • その後、 try_boot_sys() を呼んで、 schedule() して activateThread() する
      • src/kernel/thread.c@schedule()
        • 11箇所くらいで呼ばれているっぽいが、その全てにおいて schedule() の呼び出し直後に activateThread() を呼んでいる
  • src/arch/x86/kernel/boot_sys.c@try_boot_sys()
    • get_p_reg_kernel_img() の戻り値をグローバル変数である boot_state_t boot_state に代入
    • cpuidを見たり、PICやらACPIやらを初期化したり
    • load_boot_module(boot_state.boot_module_start, load_paddr) の戻り値を load_paddr に代入して、 boot_state.ui_info の諸々を調整している
      • include/arch/x86/arch/kernel/boot_sys.h の定義を見るところだと、User Image info っぽい
    • try_boot_sys_node(boot_state.cpus[0])
  • src/arch/x86/kernel/boot_sys.c@try_boot_sys_node()
    • setCurrentVSpaceRoot(kpptr_to_paddr(X86_KERNEL_VSPACE_ROOT), 0) ← 大事そう
    • init_sys_state() を呼んでおしまい
  • src/arch/x86/kernel/boot.c@init_sys_state()
    • arch_init_freemem() を呼んでおり、これは init_freemem() を呼んでいる
      • src/kernel/boot.c@init_freemem(word_t n_available, p_region_t* available, n_reserved, *reserved, ...)
        • まず ndks_boot.freemem の全要素に REG_EMPTYstart == end == 0 な region)を代入して初期化
          • ndks_boot_t ndks_boot はグローバル変数
          • ndks って何?
        • a と r を [0, n_available), [0, n_reserved) の範囲でイテレート
          • ↓このへん正直よくわからん
          • reserved[r] について start == end なら空なので r++ してスキップ
          • avail_reg[a].start >= avail_reg[a].end も空なので a++ してスキップ
          • reserved[r].end <= avail_reg[a].start は予約領域が利用可能領域より下にあるので予約
          • reserved[r].start >= avail_reg[a].end はその逆
          • これらのどれにも当てはまらなかったとき、 insert_region() によって empty な ndks_boot.freemem{begin = avail_reg[a].begin, end = reserved[r].start } な region を代入
            • 当てはまらない(reserve.end > avail.start && reserve.start < avail.end)ということはつまり、reserve region が完全に avail region の中にいるということかな
      • その後、空ではない ndks_boot.freemem[i] を順に見ていって、十分な大きさの領域があったら、それを create_rootserver_objects() に渡して呼んでいる
        • 十分な~←calculate_rootserver_size() で計算した sizendks_boot.freemem[i].end から引いてごにょごにょ 何をやっているのか分かるけど言語化が難しい
        • src/kernel/boot.c@create_rootserver_objects(pptr_t start, ...)
          • rootserver_mem.start = start;
          • rootserver.(cnode|vspace|tcb) といったカーネルオブジェクトが alloc_rootserver_obj() によって初期化される
            • rootserver_mem_t rootserver はグローバル変数
    • root_cnode_cap = create_root_cnode()
      • src/kernel/boot.c@create_root_cnode()
        •  
        cap_t cap = cap_cnode_cap_new(
        CONFIG_ROOT_CNODE_SIZE_BITS, /* radix /
        wordBits - CONFIG_ROOT_CNODE_SIZE_BITS, /
        guard size /
        0, /
        guard /
        rootserver.cnode); /
        pptr */
        write_slot(SLOT_PTR(rootserver.cnode, seL4_CapInitThreadCNode), cap);
        return cap;
        ```
        • #define SLOT_PTR(pptr, pos) (((slot_ptr_t)(pptr)) + (pos))
          • pptr って何?
            • Physical Ptr らしい
        • cap は CNode capability ということになる
          • rootserver.cnode を操作できる Capability を作成している、ということかな
        • write_slot() はつまり rootserver.cnode[seL4_CapInitThreadCNode] = cap をしているのと同等
    • create_initial_thread()
      • src/kernel/boot.c@create_initial_thread()
        • 大事そう:
          • cteInsert(
                root_cnode_cap,
                SLOT_PTR(pptr_of_cap(root_cnode_cap), seL4_CapInitThreadCNode),
                SLOT_PTR(rootserver.tcb, tcbCTable)
            );
          • #define pptr_of_cap(cap) ((pptr_t)cap_get_capPtr(cap))
            • src/object/objecttype.c@cap_get_capPtr(cap_t)cap_get_capType()cap_tag_t ctag を得て、これを switch し、タイプに応じて処理
              • Untyped Capability なら return WORD_PTR(cap_untyped_cap_get_capPtr(cap)) となる
          • rootserver.tcb[tcbCTable] = root_cnode_cap[seL4_CapInitThreadCNode] 的な意味合いなのだろう
          • src/object/cnode.c@cteInsert(cap_t newCap, cte_t *srcSlot, cte_t *destSlot)
            • mdb という単語が出てきたが、何の略なのかわからない
        • write_slot(SLOT_PTR(pptr_of_cap(root_cnode_cap), seL4_CapInitThreadTCB), cap)
        • CONFIG_DEBUG_BUILD が define されていたら、setThreadName(tcb, "rootserver") する
    • create_untypes(root_cnode_cap)