linux、內核源碼、內核編譯與配置、內核模塊開發、內核啓動流程(轉)

linux是如何組成的?
答:linux是由用戶空間和內核空間組成的
爲何要劃分用戶空間和內核空間?
答:有關CPU體系結構,各處理器能夠有多種模式,而LInux這樣的劃分是考慮到系統的
安全性,好比X86能夠有4種模式RING0~RING3  RING0特權模式給LINUX內核空間RING3給用戶空間
linux內核是如何組成的?
答:linux內核由SCI(System Call Interface)系統調用接口、PM(Process Management)進程管理、MM(Memory Management)內存管理、Arch、
VFS(Virtual File Systerm)虛擬文件系統、NS(Network Stack)網絡協議棧、DD(Device Drivers) 設備驅動


linux 內核源代碼

linux內核源代碼是如何組成或目錄結構?
答:   arc目錄    存放一些與CPU體系結構相關的代碼  其中第個CPU子目錄以分解boot,mm,kerner等子目錄
block目錄    部分塊設備驅動代碼
crypto目錄    加密、壓縮、CRC校驗算法
documentation    內核文檔
drivers        設備驅動
fs        存放各類文件系統的實現代碼
include        內核所須要的頭文件。與平臺無關的頭文件入在include/linux子目錄下,與平臺相關的頭文件則放在相應的子目錄中
init        內核初始化代碼
ipc        進程間通訊的實現代碼
kernel        Linux大多數關鍵的核心功能者是在這個目錄實現(程序調度,進程控制,模塊化)
lib        庫文件代碼
mm        與平臺無關的內存管理,與平臺相關的放在相應的arch/CPU目錄    net        各類網絡協議的實現代碼,注意而不是驅動
samples     內核編程的範例
scripts        配置內核的腳本
security    SElinux的模塊
sound        音頻設備的驅動程序
usr        cpip命令實現程序
virt        內核虛擬機


內核配置與編譯
1、清除
make clean    刪除編譯文件但保留配置文件
make mrproper    刪除全部編譯文件和配置文件
make distclean    刪除編譯文件、配置文件包括backup備份和patch補丁  
2、內核配置方式
make config    基於文本模式的交互式配置
make menuconfig    基於文本模式的菜單配置
make oldconfig    使用已有的配置文件(.config),但配置時會詢問新增的配置選項
make xconfig    圖形化配置

3、make menuconfig一些說明或技巧
在括號中按「y」表示編譯進內核,按「m」編譯爲模塊,按「n」不選擇,也能夠按空格鍵進行選擇
注意:內核編譯時,編譯進內核的「y」,和編譯成模塊的「m」是分步編譯的

4、快速配置相應體系結構的內核配置
咱們能夠    到arch/$cpu/configs目錄下copy相應的處理器型號的配置文件到內核源目錄下替換.config文件

5、編譯內核
1.
————————————————————————————
make zImage   注:zImage只能編譯小於512k的內核
make bzImage
一樣咱們也能夠編譯時獲取編譯信息,可以使用
make zImage V=1
make bzImage V=1
編譯好的內核位於    arch/$cpu/boot/目錄下
————————————————————————————


以上是編譯內核make menuconfig時先「m」選項的編譯  接下來到編譯「y」模塊,也就是編譯模塊
2.
make modules    編譯內核模塊
make modules_install    安裝內核模塊 ------>這個選項做用是將編譯好的內核模塊從內核源代碼目錄copy至/lib/modules下

6、製做init ramdisk
mkinitrd initrd-$version $version
/****  mkinitrd initrd-$(可改)version $version(不可改,由於這version是尋找/lib/modules/下相應的目錄來製做)  ****/

7、內核安裝
複製內核到相關目錄下再做grub引導也就能夠了
1.cp arch/$cpu/boot/bzImage /boot/vmlinux-$version
2.cp $initrd /boot/
3.修改引導器/etc/grub.conf(lio.conf)正確引導便可




#incldue <linux/init.h>
#include <linux/module.h>

static int hello_init(void)
{
printk(KERN_WARNING"Hello,world!\n");
return 0;
}

static void hello_exit(void)
{
printk(KERN_INFO"Good,world!\n");
}

module_init(hello_init);
module_exit(hello_exit);

___________hello,world!範例___________________
1、必需模塊函數
1.加載函數    module_init(hello_init);    經過module_init宏來指定
2.卸載函數    module_exit(hello_exit);    經過module_exit宏來指定

編譯模塊多使用makefile

2、可選模塊函數
1.MODULE_LICENSE("*******");     許可證申明
2.MODULE_AUTHOR("********");    做者申明
3.MODELE_DESCRIPTION("***");    模塊描述
4.MODULE_VERSION("V1.0");    模塊版本
5.MODULE_ALIAS("*********");    模塊別名

3、模塊參數
經過宏module_param指定模塊參數,模塊參數用於在加載模塊時傳遞參數模塊
module_param(neme,type,perm);
name是模塊參數名稱
type是參數類型  type常見值:boot、int、charp(字符串型)
perm是參數訪問權限 perm常見值:S_IRUGO、S_IWUSR
S_IRUGO:任何用戶都對sys/module中出現的參數具備讀權限
S_IWUSR:容許root用戶修改/sys/module中出現的參數
/*****——————範例————————*******/
int a = 3;
char *st;
module_param(a,int,S_IRUGO);
module_param(st,charp,S_IRUGO);

/*********————結束——————**********/

/**********----makefile範例----*************/

ifneq    ($(KERNELRELFASE),)

obj-m    :=    hello.o    //這裏m值多用 obj-(CONFIG_**)代替

else

KDIR    :=    /lib/modules/$version/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symyers
endif

/*****這裏能夠擴展多文件makefile 多個obj-m***********end***************/


/******模塊參數*****/
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");

static char *name = "Junroc Jinx";
static int age = 30;

module_param(arg,int,S_IRUGO);
module_param(name,charp,S_IRUGO);

static int hello init(void)
{
printk(KERN_EMERG"Name:%s\n",name);
printk(KERN_EMERG"Age:%d\n",age);
return 0;
}

static void hello_exit(void)
{
printk(KERN_INFA"Module Exit\n");
}

moduleJ_init(hello_init);
module_exit(hello_exit);
/****************/


----------------------------------------------------------------------------
/proc/kallsyms 文檔記錄了內核中全部導出的符號的名字與地址
什麼是導出?
答:導出就是把模塊依賴的符號導進內核,以便供給其它模塊調用
爲何導出?
答:不導出依賴關係就解決不了,導入就失敗

符號導出使用說明:
EXPORT_SYMBOL(符號名)
EXPORT_SYMBOL_GPL(符號名)
其中EXPORT_SYMBOL_GPL只能用於包含GPL許可證的模塊

模塊版本不匹配問題的解決:
一、使用 modprobe --force-modversion    強行插入
二、確保編譯內核模塊時,所依賴的內核代碼版本等同於當前正在運行的內核   uname -r
----------------------------------------------------------------------
printk內核打印:
printk容許根據嚴重程度,經過附加不一樣的「優先級」來對消息分類
在<linux/kernel.h>定義了8種記錄級別。按照優先級遞減分別是:
KERN_EMERG    "<0>"    用於緊急消息,經常崩潰前的消息
KERN_ALERT    "<1>"    須要馬上行動的消息
KERN_CRIT    "<2>"    嚴重狀況
KERN_ERR    "<3>"    錯誤狀況
KERN_WARNING    "<4>"    有問題的警告
KERN_NOTICE    "<5>"    正常狀況,可是仍然值得注意
KERN_INFO    "<6>"    信息型消息
KERN_DEBUG    "<7>"    用於調試消息

沒有指定優先級的printk默認使用
DEFAULT_MESSAGE_LOGLEVEL優先級    它是一個在kernel/printk.c中定義的整數

控制優先級的配置:
/proc/sys/kernel/printk(能夠查看或修改)

/*******符號symbol各模塊依賴範例*****/

--------/********hello.c*********/----
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Junroc Jinx");
MODULE_DESCRIPTION("hello,world module! ");
MODULE_ALIAS("A simple modle test");

extern int add_integar(int a,int b);
extern int sub_integar(int a,int b);

static int __init hello_init()
{
int res = add_integar(1,2);
return 0;
}

static void __exit hello_exit()
{
int res = sub_integar(2,1);
}

module_init(hello_init);
module_exit(hello_exit);

/******hello.c****end**********/

/********start*****calculate.c******/
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

int add_integar(int a,int b)
{
return a+b;
}

int sub_integar(int a,int b)
{
return a-b;
}

static int __init sym_init()
{
return 0;
}
static void __exit sym_exit()
{

}

module_init(sym_init);
module_exit(sym_exit);

//EXPORT_SYMBOL(add_integar);
//EXPORT_SYMBOL(sub_integar);

/***********end*****calculte.c****/linux

相關文章
相關標籤/搜索