这介绍 FreeBSD 的 kernel, 目前暂不包含 SMP 的部分. 我是以我个人的想法去记录下, 当我看到 code 时脑中的想法. 如果你有什麽建议, 能让你更容易看懂, 请 mail 给我. 谢谢! i386/i386/locore.s boot loader 将 kernel binary 读入 memory 後, kernel 的进入点. i386/i386/machdep.c 和机器相关之 function. i386/i386/pmap.c physcial mapping module. kern/init_main.c 执行 sub-system 的初始. vm/vm_init.c vm sub-system 初始. vm/vm_page.c vm_page module. vm/vm_object.c vm_object module.
----------------------------------------------- i386/i386/locore.s
当 boot loader load kernel 之後, i386/i386/locore.s 为 kernel 的进入点. 第一个被执行的 code 为 label btext 所标 示的 assembly code.
boot manager (bootstrap) 会从 stack 传入. 最主要的的参数是 bootinfo, 开机时使用者所下的参数和 bios 资料. 248 行 call recover_bootinfo, recover_bootinfo 即从 stack 取得 bootinfo, 即之存入变数 _bootinfo, 让以後的 C code 可以直接以 global 变数(bootinfo)读使.
256 行, 设立之一个新的 stack 供之後的 instruction 使用. stack 之所以在此设立, 是因为我们必需先从旧的 stack 取得 bootinfo 的 内容, 然後才可以设立新的 stack, 丢弃旧的 stack.
258 行, call identify_cpu 以辨别 CPU 的型号. identify_cpu 会设 定几个 global 变数. _cpu CPU 的种类, 为 32 bits 的整数, 所有的 constant 都定义在 i386/include/cputypes.h, 45行-60行. 相对应的文字和 CPU 分类, 定义在 i386/i386/identcpu.c , 89行, i386_cpus. _cpu_vendor CPU 造商. _cpu_id CPU 的 ID. 也许就是 Intel 所提的序号. _cpu_feature unknow ???
303-309 行, 清除 bss.
311 行, call create_pagetable. 设定进行入 protected mode 之後, enable paging 所需的 page table. create_pagetable 的说明请见 後面的说明.
316-336行, enable paging mechanical. 在此, IP register 的 value 为 kernel 的 physical address, 因此会使用到 create_pagetable 920-923行, 重 mapping 的 page table.
347-348行, 以 ret 的方式跳到 begin 执行. 在执行完 ret 後, IP register 将指到我们所期望的 KERNBASE virtual address.
353-359行, 重新设立 stack 和 PCB.
363行, call _init386, i386/i386/machdep.c, 1802行, function init386. 传入 physfree, 尚未使用的 free memory. init386 设定各种 cpu 会使用到的 table, 如 gdt, ldt, idt, tss. 并进行 proc0 的资料设定. init386 所进行的工作为杂, 主要是进行初始化 的动作, 以让机器(CPU+内部装置)可以顺利的在 protected mode 运作. 详细动作, 请见专篇报导.
377行, call _mi_startup, 执行 mi_startup 函数, kern/init_main.c, 171行. 从此开始, 正式进入 kernel 的核心部分.
create_pagetable: 744行, 746-778行, 计算出 kernel 结束的位址, 并设立两个 global 变数, _KERNend kernel 的结束位址. physfree 尚未使用的记忆. 在初使阶段, physical address 的配置是从 kernel 之後的空间, 依序配置. 在此设立此变数, 以记录目前 可用空间的开始位置. 781-814行, 为各种系统资料配置记忆空间. _KPTphys kernel 所使用的 page table. 共 NKPT 个 page. (physical address) _IdlePTD page table directory. 有关 page table 架构, 请参考 Intel 所出的 programming guide. (physical address) p0upa UPAGE (physical address) _proc0paddr (virtual address) vm86phystk _vm86pa _vm86paddr (virtual address) 831-935行, 设定 page table. 将所有上面配置的空间和 kernel 所占之间空 依 physical addr 顺序, map 到 virtual address 的 KERNBASE 位址. 831-834行, 将 kernel 的 text section map 成为 read only page. 837-851行, 将 kernel 的 data, bss 和symbols map 成为 read-write page. .......... 920-923行, 将第一个 page table map 到 page directory 的第一个 entry. 这一个 page table 将会"暂时"在 page directory map 两次. 主要是因为目前的指令实际执行的 address 为 physical address, 当一开始 enable paging 时, 将会 产生一个模糊地带, 使的我们 address 依然是以 physcial address 的值进行 map, 而不是我们所希望的 KERNBASE 为其 base. 因此, 我们做此 map, 以便在 enable paging 之後, 可以顺利的执行正确的 code. 926-929行, 将 _KPTphys 安装在 page table directory(PDE) 正确的位置, 使 kernel map 到 KERNBASE. 932-935行, 将 PDE 安装在 PDE 上, 这是一个 recursive 的做法, 如 此会使的 PDE 在第二层 mapping 时, 转而成为 page table, 使的原本 PDE 所 mapping 的 page table 反而成为最後的 destination memory. 我们可以直接透过 mapping 直接读每 一个 page table. |