FreeBSD?kernel
是一個膨大的系統
,?
對于這樣一個大系統
,?
里面往往包含了大量的子系統和
??
模塊
,
當系統初始化時這些模塊就需要初始化
,?
按照通常的思路
,
這些初始化過程必須在某處
??
被顯式地調用
,
這樣一來
,
當你新增某個模塊
,
你必須再修改那個系統初始化的地方來調用這
??
個新增模塊的初始化過程
,?
而且由于
ANSI?C
語言的限制
,
調用某個函數最好先聲明
,
這樣當系
??
統的初始化過程開始增加時
,?
那個調用初始化過程的文件開始大量包含那些本來不相關的頭
??
文件
,?
偶合度就增加了
,?
這是一種不好的設計
.??
FreeBSD
為了應付這種情況
,?
使用一種叫做
SYSINIT
的機制
.?
我們知道
FreeBSD
使用一種叫做
??
ELF
的二進制目標執行文件格式
.?
這種文件格式允許文件內部組織成結構化的方式
,?
文件內
??
部可以由不同的組成部分
(section),?FreeBSD
正是利用了這種機制
.???
FreeBSD
使用
GNU?GCC
作為其
C
語言編譯器
,?
這種編譯器允許在
C
源程序中嵌入匯編語言代碼
,??
FreeBSD
通過在
C
源程序中加入匯編指令來在目標文件中增加額外的
section,?
在文件
??
/sys/sys/linker_set.h
中定義如下
:??
#ifdef?__alpha__??
#define?MAKE_SET(set,?sym)??????????????????????????????????????????????\??
????????static?void?const?*?const?__set_##set##_sym_##sym?=?&sym;???????\??
????????__asm(".align?3");??????????????????????????????????????????????\??
????????__asm(".section?.set."?#set?",\"aw\"");?????????????????????????\??
????????__asm(".quad?"?#sym);???????????????????????????????????????????\??
????????__asm(".previous")??
#else??
#define?MAKE_SET(set,?sym)?????
#define?MAKE_SET(set,?sym)??????????????????????????????????????????????\??
????????static?void?const?*?const?__set_##set##_sym_##sym?=?&sym;???????\??
????????__asm(".section?.set."?#set?",\"aw\"");?????????????????????????\??
????????__asm(".long?"?#sym);???????????????????????????????????????????\??
????????__asm(".previous")??
#endif??
#define?TEXT_SET(set,?sym)?MAKE_SET(set,?sym)??
#define?DATA_SET(set,?sym)?MAKE_SET(set,?sym)??
程序一旦在某處調用
DATA_SET
宏指令
,?
就會將相應的匯編符號加入到目標文件
.?
例如
:??
int?myint;??
DATA_SET(myset,?myint);??
這兩句話將導致在目標文件中創建一個
myset?section,?
并且
myint
的地址將被放入這個
??
section
中
.??
系統的初始化必須按嚴格的順序進行
,?
為此
FreeBSD
定義了很多子系統的順序號
,?
這些順序
??
連同
SYSINIT
的許多相關定義在
/sys/sys/kernel.h
頭文件中
:??
enum?sysinit_sub_id?{??
????????SI_SUB_DUMMY????????????=?0x0000000,????/*?not?executed;?for?linker*/??
????????SI_SUB_DONE?????????????=?0x0000001,????/*?processed*/??
????????SI_SUB_CONSOLE??????????=?0x0800000,????/*?console*/??
????????SI_SUB_COPYRIGHT????????=?0x0800001,????/*?first?use?of?console*/??
????????SI_SUB_TUNABLES?????????=?0x0700000,????/*?establish?tunable?values?*/??
????????SI_SUB_VM???????????????=?0x1000000,????/*?virtual?memory?system?init*/??
????????SI_SUB_KMEM?????????????=?0x1800000,????/*?kernel?memory*/??
????????SI_SUB_KVM_RSRC?????????=?0x1A00000,????/*?kvm?operational?limits*/??
????????SI_SUB_CPU??????????????=?0x1e00000,????/*?CPU?resource(s)*/??
????????SI_SUB_KLD??????????????=?0x1f00000,????/*?KLD?and?module?setup?*/??
????????SI_SUB_INTRINSIC????????=?0x2000000,????/*?proc?0*/??
????????SI_SUB_VM_CONF??????????=?0x2100000,????/*?config?VM,?set?limits*/??
????????SI_SUB_RUN_QUEUE????????=?0x2200000,????/*?the?run?queue*/??
????????SI_SUB_CREATE_INIT??????=?0x2300000,????/*?create?the?init?process?*/??
????????SI_SUB_DRIVERS??????????=?0x2400000,????/*?Let?Drivers?initialize?*/??
????????SI_SUB_CONFIGURE????????=?0x3800000,????/*?Configure?devices?*/??
????????SI_SUB_VFS??????????????=?0x4000000,????/*?virtual?file?system*/??
????????SI_SUB_CLOCKS???????????=?0x4800000,????/*?real?time?and?stat?clocks*/??
????????SI_SUB_MBUF?????????????=?0x5000000,????/*?mbufs*/??
????????SI_SUB_CLIST????????????=?0x5800000,????/*?clists*/??
????????SI_SUB_SYSV_SHM?????????=?0x6400000,????/*?System?V?shared?memory*/??
????????SI_SUB_SYSV_SEM?????????=?0x6800000,????/*?System?V?semaphores*/??
????????SI_SUB_SYSV_MSG?????????=?0x6C00000,????/*?System?V?message?queues*/??
????????SI_SUB_P1003_1B?????????=?0x6E00000,????/*?P1003.1B?realtime?*/??
????????SI_SUB_PSEUDO???????????=?0x7000000,????/*?pseudo?devices*/??
????????SI_SUB_EXEC?????????????=?0x7400000,????/*?execve()?handlers?*/??
????????SI_SUB_PROTO_BEGIN??????=?0x8000000,????/*?XXX:?set?splimp?(kludge)*/??
????????...??
};??
子系統內還有順序號
:??
enum?sysinit_elem_order?{??
????????SI_ORDER_FIRST??????????=?0x0000000,????/*?first*/??
????????SI_ORDER_SECOND?????????=?0x0000001,????/*?second*/??
????????SI_ORDER_THIRD??????????=?0x0000002,????/*?third*/??
????????SI_ORDER_MIDDLE?????????=?0x1000000,????/*?somewhere?in?the?middle?*/??
????????SI_ORDER_ANY????????????=?0xfffffff?????/*?last*/??
};??
FreeBSD
為每個想要在系統初始化時被調用的函數
,?
定義兩個函數類型
:??
typedef?void?(*sysinit_nfunc_t)?__P((void?*));??
typedef?void?(*sysinit_cfunc_t)?__P((const?void?*));??
它們是系統初始化被調用時使用的函數原型
.??
兩個重要的宏使得初始化函數能夠在系統開始時被執行
:??
#define?C_SYSINIT(uniquifier,?subsystem,?order,?func,?ident)????\??
????????static?struct?sysinit?uniquifier?##?_sys_init?=?{???????\??
????????????????subsystem,??????????????????????????????????????\??
????????????????order,??????????????????????????????????????????\??
????????????????func,???????????????????????????????????????????\??
????????????????ident???????????????????????????????????????????\??
????????};??????????????????????????????????????????????????????\??
????????DATA_SET(sysinit_set,uniquifier?##?_sys_init);??
#define?SYSINIT(uniquifier,?subsystem,?order,?func,?ident)??????\??
????????C_SYSINIT(uniquifier,?subsystem,?order,?????????????????\??
????????(sysinit_cfunc_t)(sysinit_nfunc_t)func,?(void?*)ident)??
其中每個初始化函數被存儲成這樣一個結構
:??
????????struct?sysinit?{??
???????????unsigned?int????subsystem;??????????????/*?subsystem?identifier*/??
???????????unsigned?int????order;??????????????????/*?init?order?within?subsystem*/??
???????????sysinit_cfunc_t?func;???????????????????/*?function?????????????*/??
???????????const?void??????*udata;?????????????????/*?multiplexer/argument?*/??
????????};??
這個結構包含了子系統編號
,?
子系統中的順序號
,?
初始化函數的地址
,?
以及這個函數
??
使用的參數
.??
現在如果有個函數想要在系統啟動時自動被調用
,?
并且知道這個函數是為
VM
子系統做準備工
??
作
,?
可以這樣申明
:??
long?myvar;??
void?init_myvar(void?*p)??
{??
?????*(long?*)p?=?2;??
}??
SYSINIT(init_myvar,?SI_SUB_VM,?1000,?init_myvar,?&myvar)??
這樣聲明的初始化過程分布在很多目標文件中
,?
當
gcc
的連接編輯器
ld
運行時就會把屬于同
??
一個
section
的數據合并到一個連續的地址塊中
.??
由于在這個
section
中包含的只能是指向
sysinit
結構的指針
,
這樣
FreeBSD
就可以把這個地址
??
當成一個
sysinit*?
的數組
,?FreeBSD
找出這個
sysinit_set
地址
,?
邊歷這個數組并調用其中
??
的初始化函數
.?
為了確切知道這個
section
的大小
(
直接讀
ELF
是可能的
,
但是那樣太復雜
,
要
??
知道
kernel
調用初始化過程時文件系統可能還沒有初始化呢
),?
系統中包含一個工具
??
gensetdefs,?
這個工具能掃描給出的一組
.o
目標文件
,?
并找到任何名字是由
.set.
開頭的
??
section,?
它統計有多少個這樣的的初始化函數
,?
并在
sysinit_set
的開頭生成一個長整形
??
計數器
.?gensetdefs
生成三個文件
:??
setdef0.c?setdef1.c?setdefs.h??
文件
setdef0.c
的內容
:??
--------------------------------------------------------??
/*?THIS?FILE?IS?GENERATED,?DO?NOT?EDIT.?*/??
#define?DEFINE_SET(set,?count)??????????????????\??
__asm__(".section?.set."?#set?",\"aw\"");???????\??
__asm__(".globl?"?#set);????????????????????????\??
__asm__(".type?"?#set?",@object");??????????????\??
__asm__(".p2align?2");??????????????????????????\??
__asm__(#set?":");??????????????????????????????\??
__asm__(".long?"?#count);???????????????????????\??
__asm__(".previous")??
#include?"setdefs.h"????????????/*?Contains?a?`DEFINE_SET'?for?each?set?*/??
--------------------------------------------------------??
這里的
DEFINE_SET
效果就是申明一
C
結構
:??
struct?linker_set?{??
????????int?????ls_length;??
????????void????*ls_items[1];???????????/*?really?ls_length?of?them,??
????????????????????????????????????????????????*?trailing?NULL?*/??
};??
文件
setdef1.c
的內容
:??
--------------------------------------------------------??
/*?THIS?FILE?IS?GENERATED,?DO?NOT?EDIT.?*/??
#define?DEFINE_SET(set,?count)??????????????????????????\??
__asm__(".section?.set."?#set?",\"aw\"");???????\??
__asm__(".long?0");?????????????????????\??
__asm__(".previous")??
#include?"setdefs.h"????????????/*?Contains?a?`DEFINE_SET'?for?each?set?*/??
這個
DEFINE_SET
在某個
section
中放入一個
?long?0.??
--------------------------------------------------------??
文件
setdefs.h
的內容
:??
DEFINE_SET(cons_set,?3);??
DEFINE_SET(kbddriver_set,?2);??
DEFINE_SET(periphdriver_set,?5);??
DEFINE_SET(scrndr_set,?9);??
DEFINE_SET(scterm_set,?1);??
DEFINE_SET(sysctl_set,?552);??
DEFINE_SET(sysinit_set,?323);??
DEFINE_SET(sysuninit_set,?155);??
DEFINE_SET(vga_set,?9);??
DEFINE_SET(videodriver_set,?4);??
當
kernel
被連接時
,?
在
Makefile
中
setdef0.o
被安排最前面
,?
這樣
ld
就把這個初始化函數的
??
計數器安排在這個
section
的最前面
.?FreeBSD?kernel
就能從這個
section
的開頭讀到這個計
??
數器
,?
也就知道了有多少個初始化函數
.?
在
Makefile
中被安排在中間的的是
FreeBSD
的其他
??
.o
文件
,?
最后由
setdef1.o
壓陣
.?setdef1.c
定義了一個空指針
,
用以表示這個
section
的結束
??
,
這種安排
,?
我把它叫做夾三明治
.??
初始化過程的調用被安排在內核
?/sys/kern/init_main.c
的
mi_startup
函數中
,?mi_startup??
是系統啟動過程中
,?
第一個被執行的
C
語言函數
,??
它做的第一件事情就是調用這些初始化函
??
數
,?
開始時對所有的初始化過程做優先級排序
,?
然后順序調用它們
.??
void??????????????????????
mi_startup(void)??
{?????????????????
??????????????????????????
????????register?struct?sysinit?**sipp;?????????/*?system?initialization*/??
????????register?struct?sysinit?**xipp;?????????/*?interior?loop?of?sort*/??
????????register?struct?sysinit?*save;??????????/*?bubble*/??
restart:??????????
??????????
????????
這是優先級別排序
,?
這里沒有使用那個在
setdef0.c
中定義的計數器
,?
而是使用
??
????????
了
setdef1.c
中定義的空指針作為結束標志
.??
??????????
????????/*????????
?????????*?Perform?a?bubble?sort?of?the?system?initialization?objects?by??
?????????*?their?subsystem?(primary?key)?and?order?(secondary?key).??
?????????*/???????
????????for?(sipp?=?sysinit;?*sipp;?sipp++)?{??
????????????????for?(xipp?=?sipp?+?1;?*xipp;?xipp++)?{??
????????????????????????if?((*sipp)->subsystem?< (*xipp)->subsystem?||??
?????????????????????????????((*sipp)->subsystem?==?(*xipp)->subsystem?&&??
??????????????????????????????(*sipp)->order?<= (*xipp)->order))??
????????????????????????????????continue;???????/*?skip*/??
????????????????????????save?=?*sipp;??
????????????????????????*sipp?=?*xipp;??
????????????????????????*xipp?=?save;??
????????????????}??
????????}??
????????/*??
?????????*?Traverse?the?(now)?ordered?list?of?system?initialization?tasks.??
?????????*?Perform?each?task,?and?continue?on?to?the?next?task.??
?????????*??
?????????*?The?last?item?on?the?list?is?expected?to?be?the?scheduler,??
?????????*?which?will?not?return.??
?????????*/??
????????for?(sipp?=?sysinit;?*sipp;?sipp++)?{??
????????????????if?((*sipp)->subsystem?==?SI_SUB_DUMMY)??
????????????????????????continue;???????/*?skip?dummy?task(s)*/??
這是按順序調用
:??
/*??
?????????*?Traverse?the?(now)?ordered?list?of?system?initialization?tasks.??
?????????*?Perform?each?task,?and?continue?on?to?the?next?task.??
?????????*??
?????????*?The?last?item?on?the?list?is?expected?to?be?the?scheduler,??
?????????*?which?will?not?return.??
?????????*/??
????????for?(sipp?=?sysinit;?*sipp;?sipp++)?{??
????????????????if?((*sipp)->subsystem?==?SI_SUB_DUMMY)??
????????????????????????continue;???????/*?skip?dummy?task(s)*/??
????????????????if?((*sipp)->subsystem?==?SI_SUB_DONE)??
????????????????????????continue;??
????????????????/*?Call?function?*/??
????????????????(*((*sipp)->func))((*sipp)->udata);??
????????????????/*?Check?off?the?one?we're?just?done?*/??
????????????????(*sipp)->subsystem?=?SI_SUB_DONE;??
????????????????/*?Check?if?we've?installed?more?sysinit?items?via?KLD?*/??
????????????????if?(newsysinit?!=?NULL)?{??
????????????????????????if?(sysinit?!=?(struct?sysinit?**)sysinit_set.ls_items)??
????????????????????????????????free(sysinit,?M_TEMP);??
????????????????????????sysinit?=?newsysinit;??
????????????????????????newsysinit?=?NULL;??
????????????????????????goto?restart;??
????????????????}??
????????}??
????????panic("Shouldn't?get?here!");??
}??
??????
SRC= http://www.moon-soft.com/program/bbs/readelite432617.htm
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
