seL4のx86_64におけるブート処理を読んでみる
src/arch/x86/(32|64)/head.S@BEGIN_FUNC(_start)- multibootから呼ばれる想定
eaxに multiboot の magic number が、ebxにmultiboot_info_ptrが入っていて、それぞれをedi, esiに入れている- SystemV ABIに則っている
jmp boot_sys
src/arch/x86/kernel/boot_sys.c@boot_sys()- 第1引数
multiboot_magicに応じてtry_boot_sys_mbi(1|2)のどちらかを呼ぶ - 第2引数
mbiはMultiBoot Infoかな - その後、
try_boot_sys()を呼んで、schedule()してactivateThread()するsrc/kernel/thread.c@schedule()- 11箇所くらいで呼ばれているっぽいが、その全てにおいて
schedule()の呼び出し直後にactivateThread()を呼んでいる
- 11箇所くらいで呼ばれているっぽいが、その全てにおいて
- 第1引数
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_EMPTY(start == 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()で計算したsizeをndks_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()
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))となる
- Untyped Capability なら
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)
