FreeBSD 4.0 Kernel Hacking Guide--i386/i386/l

3/28/2005来源:FreeBSD教程人气:10911


这介绍 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.