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 核心虛擬機器
核心配置與編譯
一、清除
make clean 刪除編譯檔案但保留設定檔
make mrproper 刪除所有編譯檔案和設定檔
make distclean 刪除編譯檔案、設定檔包括backup備份和patch補丁
二、核心配置方式
make config 基於文字模式的互動式配置
make menuconfig 基於文字模式的菜單配置
make oldconfig 使用已有的設定檔(.config),但配置時會詢問新增的配置選項
make xconfig 圖形化配置
三、make menuconfig一些說明或技巧
在括弧中按“y”表示編譯進核心,按“m”編譯為模組,按“n”不選擇,也可以按空格鍵進行選擇
注意:核心編譯時間,編譯進核心的“y”,和編譯成模組的“m”是分步編譯的
四、快速配置相應體繫結構的核心配置
我們可以 到arch/$cpu/configs目錄下copy相應的處理器型號的設定檔到核心來源目錄下替換.config檔案
五、編譯核心
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下
六、製作init ramdisk
mkinitrd initrd-$version $version
/**** mkinitrd initrd-$(可改)version $version(不可改,因為這version是尋找/lib/modules/下相應的目錄來製作) ****/
七、核心安裝
複製核心到相關目錄下再作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.載入函數 module_init(hello_init); 通過module_init宏來指定
2.卸載函數 module_exit(hello_exit); 通過module_exit宏來指定
編譯模組多使用makefile
二、可選模組函數
1.MODULE_LICENSE("*******"); 許可證申明
2.MODULE_AUTHOR("********"); 作者申明
3.MODELE_DESCRIPTION("***"); 模組描述
4.MODULE_VERSION("V1.0"); 模組版本
5.MODULE_ALIAS("*********"); 模組別名
三、模組參數
通過宏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許可證的模組
模組版本不匹配問題的解決:
1、使用 modprobe --force-modversion 強行插入
2、確保編譯核心模組時,所依賴的核心代碼版本等同於當前正在啟動並執行核心 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****/