連建永,顧忠明,張安琳,黃道穎★,張安琴
(1.鄭州輕工業(yè)學(xué)院,鄭州 450002;2.中國建設(shè)銀行江蘇省分行,南京 210002)
指控系統(tǒng)中多操作系統(tǒng)啟動(dòng)工具的研究*
連建永1,顧忠明1,張安琳1,黃道穎1★,張安琴2
(1.鄭州輕工業(yè)學(xué)院,鄭州 450002;2.中國建設(shè)銀行江蘇省分行,南京 210002)
指控系統(tǒng)中GRUB2作為啟動(dòng)引導(dǎo)器,管理多種操作系統(tǒng)平臺(tái)。GRUB2采用模塊化設(shè)計(jì),可以提供給使用者更大的靈活性和性能改進(jìn)。Linux系統(tǒng)的模塊化設(shè)計(jì)與運(yùn)行機(jī)制已被廣泛討論,有關(guān)GRUB2的模塊化設(shè)計(jì)與運(yùn)行機(jī)制的資料卻很少。為了了解它的模塊化編程與運(yùn)行機(jī)制,通過對(duì)一個(gè)模塊程序的分析,介紹了GRUB2中模塊程序的基本結(jié)構(gòu)及模塊化設(shè)計(jì)的靈活性;并討論了GRUB2的模塊運(yùn)行機(jī)制,明確了模塊運(yùn)行所需的底層工作。在此基礎(chǔ)上,可以對(duì)GRUB2進(jìn)行二次開發(fā),擴(kuò)展其應(yīng)用場合。
GRUB2,操作系統(tǒng),模塊機(jī)制,可加載模塊
在指控系統(tǒng)中,為滿足各種不同的應(yīng)用,使用了多種操作系統(tǒng),在多個(gè)操作系統(tǒng)的應(yīng)用平臺(tái)中,如何管理和啟動(dòng)這些操作系統(tǒng),并加入自己的系統(tǒng)管理功能,一直是困擾科研人員的問題,為此,引入GRUB2并在其上進(jìn)行二次開發(fā),設(shè)計(jì)了新的GRUB(GRand Unified Bootloader)啟動(dòng)引導(dǎo)器,用于實(shí)現(xiàn)管理和啟動(dòng)指控系統(tǒng)中的多個(gè)操作系統(tǒng)并實(shí)現(xiàn)特定系統(tǒng)功能。GRUB是目前技術(shù)比較先進(jìn)、開放源代碼的較為安全的多操作系統(tǒng)啟動(dòng)管理工具,它由Erich和Brian Ford在 1995年設(shè)計(jì),歷經(jīng)多年,已由GRUB Legacy發(fā)展到了GRUB2。經(jīng)過重寫,GRUB2在編碼規(guī)范和體系結(jié)構(gòu)完全不同于GRUB Legacy,更加規(guī)范、安全、健壯和可擴(kuò)展,可以提供給使用者更大的靈活性和性能改進(jìn)。
GRUB2具有模塊化、層次化、基于對(duì)象的框架,在此框架基礎(chǔ)上進(jìn)行二次開發(fā),可以生成操作系統(tǒng)多版本啟動(dòng)管理系統(tǒng)滿足前述需求。
與Linux的LKM(LoadableKernelModule)機(jī)制[1]類似,GRUB2采用了模塊化設(shè)計(jì),又加上它是開源設(shè)計(jì),在操作系統(tǒng)的啟動(dòng)管理等方面吸引了眾多人員的研究。但由于GRUB2的模塊程序的設(shè)計(jì)與調(diào)試是基于類Linux的微內(nèi)核環(huán)境,和Linux有著一定的不同,許多程序員對(duì)GRUB2的模塊程序的基本結(jié)構(gòu)不太了解,對(duì)GRUB2的進(jìn)一步開發(fā)造成了諸多不便。這就是本文討論GRUB2的模塊程序的基本結(jié)構(gòu)和模塊機(jī)制的原因。
雖然GRUB2模塊程序的設(shè)計(jì)與調(diào)試是基于類Linux的微內(nèi)核環(huán)境,GRUB2的模塊化設(shè)計(jì)和Linux有著一定差異,但前者的基本思想?yún)s是借鑒了Linux的,因此,兩者有著異曲同工之處。在Linux的LKM中,一個(gè)內(nèi)核模塊程序至少包含兩個(gè)函數(shù):模塊被加載時(shí)執(zhí)行的入口函數(shù)mod_entry_func()和模塊被卸載時(shí)執(zhí)行的結(jié)束函數(shù)mod_exit_func()(在最新內(nèi)核中兩函數(shù)可以任意命名),通過宏module_init()和module_exit()實(shí)現(xiàn)。類似于Linux的模塊程序中的module_init()和module_exit(),GRUB2的模塊程序包含初始化函數(shù)GRUB_MOD_INIT()和結(jié)束函數(shù)GRUB_MOD_FINI(),用于模塊程序的初始化和釋放;同時(shí)還有一個(gè)完成模塊功能的函數(shù)grub_cmd_##name##。
以Hello World為例來說明GRUB2模塊程序是怎樣的結(jié)構(gòu)。以grub-1.97~beta4版本中的模塊程序hello.c為例,如下:
這個(gè)程序主要包括3個(gè)部分:grub_cmd_hello()、GRUB_MOD_INIT(hello)、GRUB_MOD_FINI(hello)。GRUB_MOD_INIT()是模塊程序的初始化函數(shù),GRUB_MOD_FINI()是模塊函數(shù)的結(jié)束函數(shù),這兩者具有較為固定的格式,而grub_cmd_hello()則是完成“Hello World”功能的函數(shù)。這些函數(shù)組成了GRUB2模塊程序的基本結(jié)構(gòu),圖1則提供了模塊程序的源代碼的基本結(jié)構(gòu)。
圖1 GRUB2的模塊程序的基本結(jié)構(gòu)
功能函數(shù)grub_cmd_##name##完成了對(duì)模塊程序?qū)崿F(xiàn)功能的定義;初始化函數(shù)GRUB_MOD_INIT()完成模塊的加載,其內(nèi)的注冊(cè)函數(shù)grub_register_extcmd()則實(shí)現(xiàn)模塊命令的注冊(cè);結(jié)束函數(shù)GRUB_MOD_FINI()則完成模塊的卸載,其內(nèi)的grub_unregister_extcmd()則對(duì)該模塊注冊(cè)的命令進(jìn)行注銷。
2.1 初始化函數(shù)
GRUB_MOD_INIT()是模塊程序的初始化函數(shù),用來初始化一個(gè)模塊。其在dl.h中的定義如下:
當(dāng)使用GRUB2內(nèi)嵌的命令insmod加載一個(gè)模塊 時(shí) ,insmod只 能 識(shí) 別 模 塊 程 序 中 的GRUB_MOD_INIT()函數(shù),所以在GRUB_MOD_INIT()中,通常會(huì)有模塊命令的注冊(cè)函數(shù)grub_register_extcmd(),其具體承擔(dān)了加載的工作。GRUB_MOD_INIT()會(huì)通過grub_register_extcmd()調(diào)用功能主體函數(shù)grub_cmd_##name##,完成模塊的加載。grub_register_extcmd()在extcmd.h中的定義如下:
其中name參數(shù)是模塊名稱,func參數(shù)為描述模塊命令功能的數(shù)據(jù)結(jié)構(gòu),flags參數(shù)為模塊命令的標(biāo)識(shí),不同的值代表著模塊命令不同的作用,summary是命令用法的概述,discritions是命令功能的描述,parser有關(guān)解釋器信息。例如在hello模塊程序中:
模塊的名稱是hello,調(diào)用grub_cmd_hello完成功能,標(biāo)識(shí)為GRUB_COMMAND_FLAG_BOTH,即可以在命令行和菜單兩個(gè)環(huán)境中運(yùn)行;命令格式為hello,功能描述為“Say hello”。
2.2 結(jié)束函數(shù)
GRUB_MOD_FINI()是模塊程序的結(jié)束函數(shù),用來釋放一個(gè)模塊,它在模塊卸載時(shí)被調(diào)用。其在dl.h中的定義為:
類似GRUB_MOD_INIT(),GRUB_MOD_FINI()中有注銷函數(shù)grub_unregister_extcmd()。卸載模塊時(shí),GRUB_MOD_FINI() 會(huì)通過 grub_unregister_extcmd()完成模塊的卸載。
2.3 功能函數(shù)
在GRUB2的模塊程序中,除去固定格式的GRUB_MOD_INI()和GRUB_MOD_FINI(),通常還要有完成模塊功能的部分,且為了代碼的規(guī)范性和易讀性,常以grub_cmd_##name##命名,且參數(shù)形式如下:
其中“__attribute__((unused)”表示該函數(shù)或變量可能為空,這個(gè)屬性可以避免編譯器產(chǎn)生警告信息。功能函數(shù)的編寫,采用ANSI C編碼規(guī)范,沒有固定的格式,且編寫復(fù)雜函數(shù)時(shí),可能需要添加新的庫函數(shù)來滿足功能的實(shí)現(xiàn)。
分析了GRUB2中模塊程序的基本結(jié)構(gòu),下面介紹模塊程序中的函數(shù)具體是怎樣加載到內(nèi)核中,而用戶又是怎樣訪問模塊中的函數(shù)、實(shí)現(xiàn)模塊功能的。
事實(shí)上,用戶不能直接訪問模塊中的函數(shù),而是通過系統(tǒng)調(diào)用進(jìn)入內(nèi)核空間,然后由內(nèi)核空間完成相應(yīng)的工作[2]。在GRUB2中通常使用內(nèi)嵌的命令insmod和rmmod來加載和卸載模塊。insmod開始加載模塊過程,通過系統(tǒng)調(diào)用將模塊二進(jìn)制文件復(fù)制到內(nèi)核空間,由內(nèi)核完成加載過程。通過rmmod卸載模塊的過程與加載過程基本類似。
3.1 模塊的加載
模塊的加載最終要實(shí)現(xiàn)模塊程序中命令的注冊(cè),則模塊的加載可以看作兩個(gè)步驟:①使用insmod將模塊掛載到內(nèi)核中,并在模塊鏈表中維護(hù)一組該模塊的狀態(tài);②內(nèi)核解析模塊程序,將模塊程序?qū)崿F(xiàn)的命令注冊(cè)到內(nèi)核中,并在命令鏈表維護(hù)一組該模塊命令的狀態(tài)量。
當(dāng)使用insmod加載一個(gè)模塊程序編譯的二進(jìn)制文件時(shí),先經(jīng)insmod進(jìn)入內(nèi)核空間,再由內(nèi)核進(jìn)行對(duì)二進(jìn)制文件的解析和操作,完成模塊命令的加載。
命令insmod定義了需要加載的模塊,通過系統(tǒng)調(diào)用,開始加載過程。insmod會(huì)做以下工作:①通過系統(tǒng)調(diào)用,申請(qǐng)足夠的內(nèi)核空間,將模塊二進(jìn)制文件拷貝到已分配空間。②每個(gè)模塊必須包含初始化函數(shù)和結(jié)束函數(shù),而只有insmod能夠識(shí)別它,因此insmod必須知道這些地址,并傳遞給內(nèi)核。③同時(shí)insmod為模塊創(chuàng)建一個(gè)關(guān)于該模塊的列表,填寫依賴關(guān)系等信息[3]。
進(jìn)入內(nèi)核空間以后,內(nèi)核首先會(huì)進(jìn)行檢查它是否一個(gè)有效的ELF文件,是否適合當(dāng)前的結(jié)構(gòu)等等。完成檢查后,就會(huì)對(duì)模塊二進(jìn)制文件進(jìn)行解析。由于insmod已將初始化函數(shù)GRUB_MOD_INIT()和結(jié)束函數(shù)GRUB_MOD_FINI()的地址傳遞給內(nèi)核,內(nèi)核會(huì)進(jìn)行對(duì)模塊函數(shù)的注冊(cè)。內(nèi)核經(jīng)過解析找到模塊程序的初始化函數(shù),并經(jīng)過多級(jí)的調(diào)用,將模塊程序所包含的命令加載到了內(nèi)核中。圖2為模塊函數(shù)在加載時(shí)具體調(diào)用的過程。
由于模塊程序中只有GRUB_MOD_INIT()和GRUB_MOD_FINI()能夠被直接識(shí)別到,所以模塊命令的注冊(cè)函數(shù)grub_register_extcmd()必須放在GRUB_MOD_INIT()中,使內(nèi)核找到注冊(cè)函數(shù)。注冊(cè)函數(shù)grub_register_extcmd()通過多級(jí)調(diào)用,調(diào)用了grub_register_command_prio()。而它才真正將模塊函數(shù)中的命令掛載到內(nèi)核中,同時(shí)將模塊命令的數(shù)據(jù)結(jié)構(gòu)注冊(cè)進(jìn)內(nèi)核的模塊命令鏈表:它將傳遞過來的參數(shù)重新分配一個(gè)數(shù)據(jù)結(jié)構(gòu)和足夠的內(nèi)存空間來保存新模塊,并按照名稱依次將它放到模塊命令鏈表上,同時(shí)定義了它的優(yōu)先級(jí)。這樣內(nèi)核才認(rèn)識(shí)了這個(gè)模塊,并且得到了該模塊的參數(shù)。
3.2 模塊的調(diào)用
將模塊加載到內(nèi)核后,內(nèi)核會(huì)維護(hù)兩組有關(guān)模塊的鏈表:模塊鏈表與命令鏈表。在命令鏈表中,各命令以struct grub_command的數(shù)據(jù)結(jié)構(gòu)按照名稱依次存儲(chǔ)著一個(gè)個(gè)命令的信息。圖3提供了一個(gè)模塊命令鏈表的簡單模型:name參數(shù)為模塊命令名稱,prio為該命令的優(yōu)先級(jí),func為命令調(diào)用的功能函數(shù),flags為標(biāo)志位,summary為命令用法的概述,discritions為命令功能的描述,data為隨機(jī)產(chǎn)生的數(shù)據(jù)。
圖3 模塊命令鏈表
當(dāng)應(yīng)用程序去調(diào)用這個(gè)模塊命令時(shí),內(nèi)核會(huì)根據(jù)用戶的命令參數(shù),查找模塊命令鏈表,找到與之對(duì)應(yīng)的模塊命令,并根據(jù)數(shù)據(jù)結(jié)構(gòu)的各項(xiàng)定義,找到對(duì)應(yīng)完成用戶要求的函數(shù),完成函數(shù)功能,如查找不到,返回錯(cuò)誤。比如,在命令行輸入“hello”命令,會(huì)傳遞到內(nèi)核,內(nèi)核會(huì)遍歷命令鏈表,查找名稱為“hello”的命令,進(jìn)而根據(jù)該模塊命令的數(shù)據(jù)結(jié)構(gòu),調(diào)用它的功能函數(shù)grub_cmd_hello,并完成其功能,則會(huì)出現(xiàn)“Hello World”字符串。
3.3 模塊的卸載
模塊的卸載過程類似模塊的加載。使用rmmod卸載模塊時(shí),首先會(huì)進(jìn)行幾個(gè)健康檢查,如參數(shù)是否正確,模塊是否存在依賴關(guān)系,確保安全刪除模塊。然后rmmod會(huì)調(diào)用grub_dl_unload(),它會(huì)修改模塊鏈表:注銷該模塊的符號(hào)輸出表,節(jié)信息表,修改依賴關(guān)系,接著開始模塊的內(nèi)核清理過程。
內(nèi)核調(diào)用模塊程序的GRUB_MOD_FINI(),并經(jīng)過多級(jí)調(diào)用,撤銷注冊(cè)函數(shù)所做的一切。模塊命令的注銷過程如圖4所示。
圖4 模塊命令的卸載過程
模塊的注銷函數(shù)grub_unregister_extcmd()放在結(jié)束函數(shù)GRUB_MOD_FINI()中。注銷函數(shù)調(diào)用了grub_unregister_command(),它將模塊命令從內(nèi)核注銷,同時(shí)將該模塊命令從內(nèi)核的模塊命令鏈表刪除,同時(shí)釋放內(nèi)存空間。之后該模塊不存在依賴項(xiàng),系統(tǒng)將這個(gè)模塊從安裝期間添加的各種列表中刪除,為模塊分配的各種內(nèi)存被釋放,包括參數(shù)內(nèi)存、鏈表內(nèi)存和模塊的ELF內(nèi)存。
通過上述一個(gè)模塊程序代碼的分析,可以得出以下結(jié)論:(1)GRUB2下的模塊程序都有一個(gè)初始化函數(shù) GRUB_MOD_INIT () 和 結(jié) 束 函 數(shù)GRUB_MOD_FINI()。
(2)當(dāng)用戶加載或者卸載模塊時(shí),會(huì)通過系統(tǒng)調(diào)用內(nèi)核函數(shù),將模塊掛載到內(nèi)核空間;接著內(nèi)核解析模塊程序,將模塊中的命令加載到內(nèi)核。
(3)利用GRUB2的模塊化設(shè)計(jì),可以進(jìn)行二次開發(fā),添加某些特殊功能的模塊,可以對(duì)指控系統(tǒng)的系統(tǒng)環(huán)境、現(xiàn)場數(shù)據(jù)和技術(shù)狀態(tài)實(shí)現(xiàn)操作系統(tǒng)級(jí)的快速還原。
[1]劉天華,陳 梟,朱宏峰,等.Linux可加載內(nèi)核模塊機(jī)制的研究與應(yīng)用[J].微計(jì)算機(jī)信息,2007,21(20):48-49,127.
[2]周應(yīng)華.對(duì)Linux可加載內(nèi)核模塊應(yīng)用框架的研究[J].計(jì)算機(jī)系統(tǒng)應(yīng)用,2007(4):69-73.
[3]孫海彬,傅 謙,徐良賢.Linux內(nèi)核模塊的實(shí)現(xiàn)機(jī)制[J].微型機(jī)與應(yīng)用.2001,15(3):29-33.
ResearchonMultipleOSBoot-loaderforCommandandControlSystems
Lian Jian-yong1,GU Zhong-ming1,Zhang An-lin1,Huang Dao-ying1*,Zhang An-qin2
(1.Zhengzhou University of Light Industry,Zhengzhou 450002,China;
2.China Construction Bank of Jiangsu Branch,Nanjing 210002,China)
As a boot loader,GRUB2 for Command and Control Systems manage a wide range of OS platform.GRUB2 uses a modular design,provided to the user greater flexibility and performance improvements.It is being discussed very clear on Linux module programming and running mechanism,but the same information about GRUB2 is seldom.In order to understand GRUB2's modular programming and running,by analyzing a module program,its basic structure of module program in the GRUB2 is introduced and the flexibility of GRUB2 modular design is showed,by discussing GRUB2 module mechanism,the underlying work solution that required to run the module is clarified.On this basis,GRUB2 can be redeveloped to consummate its functions and extend its application occasions.
GRand Unified Bootloader 2,OS,Module Mechanism,LKM(Loadable Kernel Module)
TP316
A
1002-0640(2014)10-0154-04
2013-09-09
2013-10-07
河南省重點(diǎn)科技攻關(guān)基金(132102210418);鄭州市科技計(jì)劃基金(112PPTGY249-7);鄭州輕工業(yè)學(xué)院研究生科技創(chuàng)新基金資助項(xiàng)目
連建永(1989- ),男,河北邯鄲人,碩士研究生。研究方向:計(jì)算機(jī)網(wǎng)絡(luò)及操作系統(tǒng)。
黃道穎(1967- ),男,河南信陽人,博士,教授,碩導(dǎo)。研究方向:計(jì)算機(jī)網(wǎng)絡(luò),分布式計(jì)算系統(tǒng)。