天天看點

Linux核心編譯與開發

一.linux核心簡介

linux kernel map:

Linux核心編譯與開發

linux 系統體系結構:

Linux核心編譯與開發

linux kernel體系結構:

arm有7種工作模式,x86也實作了4個不同級别ring0-ring3,ring0級别最高,

這樣linux使用者代碼運作在ring3下,核心運作在ring0,這樣系統本身就得到了

充分的保護

使用者空間(使用者模式)轉到核心空間(系統模式)方法:

系統調用

硬體中斷

linux kernel 體系結構:

Linux核心編譯與開發

虛拟檔案系統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/build 

all: 

#kdir    依賴核心子產品源代碼路徑(核心編譯安裝路徑) 

#pwd     表示核心代碼在哪(目前目錄) 

#modules 編譯的是子產品 

    make -c $(kdir) m=$(pwd) modules  

clean: 

    rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order 

endif 

2)moduledep/2(兩個子產品的編譯)

#include <linux/module.h>  

#include <linux/init.h>  

//子產品可選資訊  

module_license("gpl");//許可證聲明  

module_author("liyuan");//作者聲明  

module_description("this module is a param example.");//子產品描述  

module_version("v1.0");//子產品别名  

module_alias("a simple module");//子產品别名  

//子產品參數 

static char *name = "liyuan arg"; 

static int age = 30; 

//s_irugo是參數權限,也可以用數字 

module_param(age,int,s_irugo); 

module_param(name,charp,s_irugo); 

//使用外部檔案函數 

extern int add(int a,int b); 

//聲明 外部核心符号 函數 

extern int add_integar(int a,int b); 

extern int sub_integar(int a,int b); 

static int __init mains_init(void) 

     //多檔案編譯 

    printk(kern_emerg"param hi"); 

    int vle=add(1,2); 

    printk(kern_emerg"add value:%d\n",vle); 

    //子產品參數 

     printk(kern_emerg" name : %s\n",name); 

     printk(kern_emerg" age : %d\n",age); 

    //使用其他子產品的函數(核心符号導出) 

    int adds=add_integar(3,1); 

    int subs=sub_integar(3,1); 

    printk(kern_emerg" add_integar : %d\n",adds); 

    printk(kern_emerg" sub_integar : %d\n",subs); 

    return 0; 

static void __exit mains_exit(void) 

    printk("param exit!"); 

module_init(mains_init);52 module_exit(mains_exit); 

add.c

int add(int a,int b) 

     return a+b; 

makefile

#兩個以上核心源檔案 生成單獨的核心子產品名ma 

#核心ma 

obj-m :=ma.o 

#下面的ma-objs前面必須和上面一樣為ma 

ma-objs := mains.o add.oelsekdir:= /lib/modules/2.6.18-53.el5/build 

        make -c $(kdir) m=$(pwd) modules  

運作帶參子產品: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

本文作者:佚名

來源:51cto

繼續閱讀