linux核心編譯與開發,linux核心編譯開發
一.Linux核心簡介
linux kernel map:
linux 系統體繫結構:
linux kernel體繫結構:
arm有7種工作模式,x86也實現了4個不同層級RING0-RING3,RING0層級最高,
這樣linux使用者代碼運行在RING3下,核心運行在RING0,這樣系統本身就得到了
充分的保護
使用者空間(使用者模式)轉到核心空間(系統模式)方法:
·系統調用
·硬體中斷
linux kernel 體繫結構:
虛擬檔案系統VFS:
VFS(虛擬檔案系統)隱藏各種檔案系統的具體細節,為檔案操作提供統一的介面
二.Linux核心原始碼
linux核心下載www.kernel.org
目錄結構:
解壓linux kernel tar後目錄
·arch:根據cpu體繫結構不同而分的代碼
·block:部分塊裝置驅動程式
·crypto:加密,壓縮,CRC校正演算法
·documentation:核心文檔
·drivers:裝置驅動程式
·fs(虛擬檔案系統vfs):檔案系統
·include:核心所需的標頭檔,(與平台無關的標頭檔在include/linux中)
·lib:庫檔案代碼(與平台相關的)
·mm:實現記憶體管理,與硬體體繫結構無關的(與硬體體繫結構相關的在arch中)
·net:網路通訊協定的代碼
·samples:一些核心編程的範例
·scripts:配置核心的指令碼
·security:SElinux的模組
·sound:音訊裝置的驅動程式
·usr:cpio命令實現,用於製作根檔案系統的命令(檔案系統與核心放到一塊的命令)
·virt:核心虛擬機器
linux DOC 編譯產生:
linux源根目錄/Documentation/00-INDEX:目錄索引
linux源根目錄/Documentation/HOWTO:指南
·產生linux核心協助文檔:在linux源根目錄(Documentation) 執行make htmldocs
ubuntu16下需要執行sudo apt-get install xmlto安裝外掛程式才可產生doc文檔
後面開發中經常要改的是arch,drivers中的代碼
三.Linux核心配置與編譯
清理檔案(在linux源碼根目錄):
·make clean:只清理所有產生的檔案
·make mrproper:清理所有產生的檔案與config設定檔
·make distclean:清理所有產生的檔案與config設定檔,並且編輯過的與補丁檔案
↓
配置(收集硬體資訊如cpu型號,網卡等...):
·make config:基於文字模式的互動配置
·make menuconfig:基於文字模式的菜單模式(推薦使用)
·make oldconfig:使用已有的.config,但會詢問新增的配置項
·make xconfig:圖形化的配置(需要安裝圖形化系統)
配置方法:
1)使用make menuconfig操作方法:
1>按y:編譯>串連>鏡像檔案
2>按m:編譯
3>按n:什麼都不做
4>按"空格鍵":y,n輪換
配置完並儲存後會在linux源碼根目錄下產生一個.config檔案
注意:在ubuntu11上要執行apt-get install libncurses5-dev來安裝支援包
2)利用已有的設定檔範本(.config)
1>linux源碼根目錄/arch/<cpu架構>/configs/<具體某一的CPU檔案>,把裡面對應的檔案copy並改名為.config至linux源碼根目錄下
2>利用當前運行已有的檔案(要用ls /boot/ -a查看)把/boot/config-2.6.18-53.e15拷貝並改名為.config至linux源碼根目錄下執行以上操作就可以用make menuconfig在拷貝
.config檔案上面修改檔案了
↓
編譯核心:
1)make zImage
2)make bzImage
區別:在X86平台上,zimage只能用於小於512k的核心
擷取詳細編譯資訊:make zimage V=1 或 make bzimage V=1
編譯好的核心在:arch/<cpu>/boot/目錄下
注意:在把.config設定檔cp到根目錄編譯核心前,必須進入make menuconfig並儲存退出(否則生不了效)
↓
編譯並安裝模組:
1)編譯核心模組:make modules
2)安裝核心模組:make modules_install INSTALL_MOD_PATH=/lib/modules
更換本機器核心:將編譯好的核心模組從核心源碼目錄copy至/lib/modules下
製作init ramdisk():輸入執行命令mkinitrd initrd-2.6.39(任意) 2.6.39(可通過查詢/lib/modules下的目錄得到)
注意:
mkinitrd命令為redhat裡面的,ubuntu的命令為:mkinitramfs -k /lib/modules/模組安裝位置 -o initrd-2.6.39(任意) 2.6.39(可通過查詢/lib/modules下的目錄得到)
如果ubuntu裡面沒有mkinitramfs命令可以用apt-get install initrd-tools進行安裝
↓
安裝核心模組:
1)手動
1>cp linux根目錄/arch/x86/boot/bzImage /boot/mylinux-2.6.39
2>cp linux根目錄/initrd-2.6.39 /boot/initrd-2.6.39
最後修改/etc/grub.conf或/etc/lilo.conf檔案
2)自動
1>make install:這個命令會自動完成上面的操作(查看當前核心版本:uname -r)
-----------------------------------------------------------------------------
四.linux核心模組開發
描述:
linux核心組件非常龐大,核心ximage並不包含某組件,而是在該組件需要被使用的時候,動態添加到正在啟動並執行核心中(也可以卸載),這種機制叫做“核心模組”的機制。核心模組通常通過使用makefile檔案對模組進行編譯
模組安裝與卸載:
1)載入:insmod hello.ko
2)卸載:rmmod hello
3)查看:lsmod
4)載入(自動尋找模組依賴):modprobe hello
modprobe會根據檔案/lib/modules/version/modules.dep來查看要載入的模組,看它是否還依賴於其他模組,如果是,會先找到這些模組,把它們先載入到核心
執行個體分析:
1)moduleDep/1(一個模組的編譯)
1 #include <linux/module.h> 2 #include <linux/init.h> 3 4 //模組入口函數 5 //__init:表示程式碼片段中的子段,裡面的內容只運行一次並且回收記憶體. 6 static int __init hello_init(void) 7 { 8 printk(KERN_EMERG "hello world!\n"); 9 return 0;10 }11 //模組卸載函數12 //__exit:13 static void __exit hello_exit(void)14 {15 printk(KERN_EMERG "hello exit!\n");16 }17 //核心符號匯出 函數18 int add_integar(int a,int b)19 {20 return a+b; 21 }22 int sub_integar(int a,int b)23 {24 return a-b; 25 }26 27 module_init(hello_init);28 module_exit(hello_exit);29 //函數匯出30 EXPORT_SYMBOL(add_integar);31 EXPORT_SYMBOL(sub_integar);
makefile:
#第一次執行KERNELRELEASE是空的,所以執行else裡面的ifneq ($(KERNELRELEASE),)obj-m :=hello.o#else塊elseKDIR:= /lib/modules/2.6.18-53.el5/buildall:#KDIR 依賴核心模組原始碼路徑(核心編譯安裝路徑)#PWD 表示核心代碼在哪(目前的目錄)#modules 編譯的是模組 make -C $(KDIR) M=$(PWD) modules clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.orderendif
2)moduleDep/2(兩個模組的編譯)
1 #include <linux/module.h> 2 #include <linux/init.h> 3 //模組可選資訊 4 MODULE_LICENSE("GPL");//許可證聲明 5 MODULE_AUTHOR("liyuan");//作者聲明 6 MODULE_DESCRIPTION("This module is a param example.");//模組描述 7 MODULE_VERSION("V1.0");//模組別名 8 MODULE_ALIAS("a simple module");//模組別名 9 10 //模組參數11 static char *name = "liyuan arg";12 static int age = 30;13 //S_IRUGO是參數許可權,也可以用數字14 module_param(age,int,S_IRUGO);15 module_param(name,charp,S_IRUGO);16 17 18 //使用外部檔案函數19 extern int add(int a,int b);20 21 22 //聲明 外部核心符號 函數23 extern int add_integar(int a,int b);24 extern int sub_integar(int a,int b);25 26 static int __init mains_init(void)27 {28 //多檔案編譯29 30 printk(KERN_EMERG"param hi");31 int vle=add(1,2);32 printk(KERN_EMERG"add value:%d\n",vle);33 //模組參數34 35 printk(KERN_EMERG" name : %s\n",name);36 printk(KERN_EMERG" age : %d\n",age);37 38 //使用其他模組的函數(核心符號匯出)39 int adds=add_integar(3,1);40 int subs=sub_integar(3,1);41 printk(KERN_EMERG" add_integar : %d\n",adds);42 printk(KERN_EMERG" sub_integar : %d\n",subs);43 return 0;44 }45 46 static void __exit mains_exit(void)47 {48 printk("param exit!");49 }50 51 module_init(mains_init);52 module_exit(mains_exit);
add.c
int add(int a,int b){ return a+b;}
makefile
ifneq ($(KERNELRELEASE),)#兩個以上核心源檔案 產生單獨的核心模組名ma#核心maobj-m :=ma.o#下面的ma-objs前面必須和上面一樣為mama-objs := mains.o add.oelseKDIR:= /lib/modules/2.6.18-53.el5/buildall: make -C $(KDIR) M=$(PWD) modules clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.orderendif
運行帶參模組:insmod hello.ko name=yuan age=12
核心符號匯出(/proc/kallsyms記錄了核心中所有匯出的符號的名字與地址):
一個核心模組的運行依賴另一個核心模組的函數實現,必須先運行第一個核心模組,這樣就需要進行核心符號匯出。
注意:
錯誤資訊:disagrees about version of symbol struct_module insmod:error inserting ...
開發核心模組時會出現,核心模組不匹配的情況.是你當前啟動並執行linux核心與編譯串連所依賴的
核心版本不匹配,解決方案:
·使用modprobe --force-modversion強行插入
·可使用uname -r進行查看當前啟動並執行核心版本
printk核心列印:
在<linux/kernel.h>中printk有8個優先順序,按優先順序遞減的是:
·KERN_EMERG 0
用於緊急的訊息,常常是那些崩潰的訊息
·KERN_ALERT 1
需要立刻行動的訊息
·KERN_CRIT 2
嚴重情況
·KERN_ERR 3
錯誤情況
·KERN_WARNING(printk預設層級) 4
有問題的警告
·KERN_NOTICE 5
正常情況,但是仍然值得注意
·KERN_INFO 6
資訊訊息
·KERN_DEBUG 7
用作調試訊息
不管是哪個層級的都會在/var/log/messages裡面列印出來(messages可以刪除後,運行核心進行測試核心列印情況)控制台列印(優先順序配置/proc/sys/kernel/printk)
6 4 1 7
·Console_loglevel
·Default_message_loglevel
·Minimum_console_level
·Default_console_loglevel
在vm+redhat安裝2.6.39核心時出現的錯誤
啟動時報could not find filesystem '/dev/root'
解決方案
a.通過make menuconfig選中以下對應的選項
General setup -->
[*] enable deprecated sysfs features to support old userspace tools
成功時下面那個也*了的
b.修改.config檔案
修改.config檔案中CONFIG_SYSFS_DEPRECATED_V2,將原本被注釋掉的
CONFIG_SYSFS_DEPRECATED_V2 改成CONFIG_SYSFS_DEPRECATED_V2=y
關注我的共用學習,討論更多技術知識
個人網站:http://www.liyuan3210.com