一.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/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