一、簡介
內核,是一個操作系統的核心。它負責管理系統的進程、內存、設備驅動程序、文件和網絡系統,決定着系統的性能和穩定性。Linux作為一個自由軟件,在廣大愛好者的支持下,內核版本不斷更新。新的內核修訂了舊內核的bug,並增加了許多新的特性。如果用戶想要使用這些新特性,或想根據自己的系統度身定制一個更高效,更穩定的內核,就需要重新編譯內核。
本文將以kernel 3.12.5版本為實驗,操作平台為RedHat 6.2,但本文所介紹的內核編譯與安裝方法適合大多數Linux系統(包括RedHat、Ubuntu、Debian等)。
二、下載新內核源碼
內核下載官網:https://www.kernel.org/
解壓內核:#tar xvf linux-3.12.5.tar.xz /opt
進入內核源碼目錄:#cd /opt/linux-3.12.5
這里解壓到任何目錄都行,本人解壓到了/opt目錄下。在網上看到很多朋友解壓到/usr/src目錄下,其實這都無所謂,因為本文所講的方法並不局限於給本機新增一個內核,還有可能是給其他機器的新增內核,就算是新增本機內核那也沒關系,因為后面執行#make install 自動就會將對應文件拷貝到本機相應的目錄下去了。
注:下文所有關於顏色標注的“3.12.5”都替換成自己實際的內核版本號。
三、替換內核
本文介紹兩種替換內核方法:編譯替換內核、打包替換內核(.deb安裝包)。
(一)編譯替換內核
編譯替換內核適合所有Linux系統,也是大多數人常用的方法。
1、定制內核
#make mrproper
作用是在每次配置並重新編譯內核前需要先執行“make mrproper”命令清理源代碼樹,包括過去曾經配置的內核配置文件“.config”都將被清除。即進行新的編譯工作時將原來老的配置文件給刪除到,以免影響新的內核編譯。
即檢查有無不正確的.o文件和依賴關系,如果使用剛下載的完整的源程序包即第一次進行編譯,那么本步可以省略。而如果你多次使用了這些源程序編譯內核,則最好要先運行一下這個命令。
#make menuconfig
注:使用make menuconfig 生成的內核配置文件,決定將內核的各個功能系統編譯進內核還是編譯為模塊還是不編譯。
在這里就不介紹具體的內核配置操作,但是建議就算不打算配置什么也執行一下make menuconfig這個命令,因為如果不執行此操作的話在后面make編譯內核的時候會提示你回答很多問題。
內核配置可參考:
Make menuconfig配置詳解:http://blog.csdn.net/xuyuefei1988/article/details/8635539
http://www.linuxidc.com/Linux/2012-06/63092.htm
配置內核還有很多其他方法,主要區別如下:
#make menuconfig //基於ncurse庫編制的圖形工具界面
#make config //基於文本命令行工具,不推薦使用
#make xconfig //基於X11圖形工具界面
#make gconfig //基於gtk+的圖形工具界面
這里選擇簡單的配置內核方法,即make menuconfig。在終端輸入make menuconfig,等待幾秒后,終端變成圖形化的內核配置界面。進行配置時,大部分選項使用其缺省值,只有一小部分需要根據不同的需要選擇。
對每一個配置選項,用戶有三種選擇,它們分別代表的含義如下:
<*>或[*]——將該功能編譯進內核
[ ]——不將該功能編譯進內核
[M]——將該功能編譯成可以在需要時動態插入到內核中的代碼
2、編譯安裝內核和模塊
(1) 拷貝.confg文件:
執行#cp /boot/config-,然后按下Tab鍵,系統會自動填上該目錄下符合條件的文件名,然后繼續輸入 .config,目的是使用在boot目錄下的原配置文件。
不執行這一步的話,后面make的時候會提示找不到.confg文件。
如果在上一步配置了內核的話應該是會自動生成.config文件,但這里本人只是執行了一次#make menuconfig命令並沒有配置內核。
(2) 建立編譯時所需的從屬文件:
#make dep
根據上一步所選擇的選項,建立文件的依賴關系。
(3) 清除內核編譯的目標文件 :
#make clean
清理一些不必要的文件,如果你在上次編譯的基礎上,刪去了一些選項,建議你執行這一步操作,否則,就沒有必要了。
(4) 編譯安裝內核和模塊:
【本機替換內核】
#make –j4
生成內核模塊和vmlinuz,initrd.img,Symtem.map文件。
注:#make相當於分別執行#make bzImage 和#make modules,由於是本機替換內核,所以無需分開執行。
這一步所需的時間較長,為了加快編譯速度,我們可以加上“-j”選項,后面跟的數字是jobsnum ,建議設置為 CPU 核心數 + 1,jobsnum值可以由命令” cat /proc/cpuinfo |sed -n '/^processor/p' |wc -l”獲得。
2)安裝模塊:
#makemodules_install
編譯成功后,系統會在/lib/modules目錄下生成一個3.12.5子目錄,里面存放着新內核的所有可加載模塊(即將編譯好的modules拷貝到/lib/modules下)。
3)安裝內核:
#makeinstall
即復制.config,vmlinuz,initrd.img,System.map文件到/boot目錄、更新grub。對於RedHat系統以下三個grub文件自動會更新,默認啟動新內核。
/etc/grub.conf
/boot/grub/menu.lst
/boot/grub/grub.conf
注:前兩個配置文件是第三個的軟連接。
Ubutun和Debian系統是/boot/grub/grub.conf文件。
4)重啟系統:
#reboot
【非本機替換內核】
在這里也可以像本機替換內核一樣直接執行#make,但本文將編譯內核和編譯模塊分開來執行,但原理和結果是一樣的。
1)編譯內核:
#make bzImage
內核編譯成功后,會在源碼樹根目錄即linux-3.12.5/arch/x86_64/boot/目錄中生成一個新內核的映像文件bzImage。
注:對於大內核(比如需要SCSI支持),make bzImage (推薦)
對於小內核,make zImage。
2)編譯模塊:
#make modules
編譯可加載模塊(即內核選項中選擇為M的選項),以便將來使用insmod命令進行加載。編譯時間跟M選項的數量有關。
3)安裝模塊:
#make modules_install
即將編譯好的modules拷貝到/lib/modules下。
4)安裝內核:
由於不是本機替換內核,所以我們需要將新生成的內核文件拷貝到要替換內核的機器上。需要拷貝的內核文件為主要有4個,分別是:.config,bzImage,System.map 和系統/lib/modules/linux-3.12.5目錄。
具體操作如下:
(1)將生成的linux-3.12.5/.config 拷貝到要替換內核系統的/boot下,並重命名為config-3.12.5
(2)將生成的linux-3.12.5/arch/x86-64/boot/bzImage 拷貝到要替換內核系統的/boot下,並重命名為vmlinuz-3.12.5(注:這里需特別注意拷貝后的文件名變為vmlinuz-x.x.x)。
(3)將生成的linux-3.12.5/System.map 拷貝到要替換內核系統的/boot下,並重命名為System.map-3.12.5
(4)將make modules_install生成的系統目錄/lib/modules/linux-3.12.5 拷貝到要替換內核系統的/lib/modules下。
(5)在要替換新內核的系統的/lib/modules目錄下執行以下命令:
#update-initramfs-c -k3.12.5,生成/boot/initrd.img-3.12.5
#update-grub(或#update-grub2), 更新啟動加載文件。
注:RedHat系統貌似是沒有以上兩個更新命令,所以以上更新內核方法適合Ubuntu或Debian系統。
那RedHat系統怎么更新內核呢?建議使用上一種【本機替換內核】方法直接make install安裝,使用【非本機替換內核】方法不太方便,但這里也做一個介紹,我們可以手動更新內核啟動文件。(當然你也可以手動下載一個grub安裝包並安裝,再使用update-grub)。
具體如下(將第(5)步替換成下面操作):
RedHat系統中有三個配置文件/etc/grub.conf;/boot/grub/menu.lst;/boot/grub/grub.conf
前兩個都是第三個的連接,所以我們只需要修改/boot/grub/grub.conf啟動配置文件即可。
內容如下:
title 顯示在啟動菜單上的名稱
root 根文件系統掛載分區,根據自身系統而定,可以仿照舊版本內核填寫。
kernel 壓縮過的內核文件名
initrd 根文件系統文件名
如:
titleMy new kernel
root (hd0,0)
kernel/boot/vmlinuz-x.y.z
initrd/boot/initrd-x.y.z.img
在紅帽系統上直接修改grub啟動文件的方法本人沒有親試,這部分內容是參照文章http://wenku.baidu.com/view/cb16a8fdc8d376eeaeaa3126.html所寫的,具體的可以看原文。
本人系統的/boot/grub/grub.conf中新增內核內容如下:
title Red Hat Enterprise LinuxServer (3.12.5)
root (hd0,0)
kernel /vmlinuz-3.12.5 orroot=/dev/……
initrd /initramfs-3.12.5.img
然后重新生成ram磁盤:
如果您的系統中的/etc/lilo.conf沒有使用了ram磁盤選項initrd,略過
如果您的系統中的/etc/lilo.conf使用了ram磁盤選項initrd,
使用mkinitrd initrd-內核版本號 內核版本號命令重新生成ram磁盤文件,例如我的Redhat 6.2:
mkinitrd initrd-3.12.5 3.12.5
之后把/etc/lilo.conf中的initrd指向新生成的initrd-3.12.5文件:
initrd=/boot/initrd-3.12.5
ram磁盤能使系統性能盡可能的優化,具體參考/usr/src/linux/Documents/initrd.txt文件
5)重啟系統:
#reboot
3、幾個重要的Linux內核文件介紹
(1).config
使用make menuconfig 生成的內核配置文件,決定將內核的各個功能系統編譯進內核還是編譯為模塊還是不編譯。
(2)vmlinuz 和 vmlinux
vmlinuz是可引導的、壓縮的內核,“vm”代表“Virtual Memory”。Linux 支持虛擬內存,不像老的操作系統比如DOS有640KB內存的限制,Linux能夠使用硬盤空間作為虛擬內存,因此得名“vm”。
vmlinuz是可執行的Linux內核,vmlinuz的建立有兩種方式:
一是編譯內核時通過“make zImage”創建,zImage適用於小內核的情況,它的存在是為了向后的兼容性;
二是內核編譯時通過命令make bzImage創建,bzImage是壓縮的內核映像,需要注意,bzImage不是用bzip2壓縮的,bzImage中的bz容易引起誤解,bz表示“big zImage”,bzImage中的b是“big”意思。 zImage(vmlinuz)和bzImage(vmlinuz)都是用gzip壓縮的。它們不僅是一個壓縮文件,而且在這兩個文件的開頭部分內嵌有gzip解壓縮代碼,所以你不能用gunzip 或 gzip –dc解包vmlinuz。內核文件中包含一個微型的gzip用於解壓縮內核並引導它。兩者的不同之處在於,老的zImage解壓縮內核到低端內存(第一個640K),bzImage解壓縮內核到高端內存(1M以上)。如果內核比較小,那么可以采用zImage 或bzImage之一,兩種方式引導的系統運行時是相同的。大的內核采用bzImage,不能采用zImage。 vmlinux是未壓縮的內核,vmlinuz是vmlinux的壓縮文件。
(3)initrd.img
initrd是“initial ramdisk”的簡寫。
initrd一般被用來臨時的引導硬件到實際內核vmlinuz能夠接管並繼續引導的狀態。比如initrd- 2.4.7-10.img主要是用於加載ext3等文件系統及scsi設備的驅動。如果你使用的是scsi硬盤,而內核vmlinuz中並沒有這個 scsi硬件的驅動,那么在裝入scsi模塊之前,內核不能加載根文件系統,但scsi模塊存儲在根文件系統的/lib/modules下。為了解決這個問題,可以引導一個能夠讀實際內核的initrd內核並用initrd修正scsi引導問題,initrd-2.4.7-10.img是用gzip壓縮的文件。initrd映象文件是使用mkinitrd創建的,mkinitrd實用程序能夠創建initrd映象文件,這個命令是RedHat專有的,其它Linux發行版或許有相應的命令。這是個很方便的實用程序。具體情況請看幫助:man mkinitrd
(4)System.map是一個特定內核的內核符號表,由“nm vmlinux”產生並且不相關的符號被濾出。
下面幾行來自/usr/src/linux-2.4/Makefile:
nm vmlinux | grep-v '(compiled)|(.o
)|(LASH[RL]DI)' | sort >System.map
在進行程序設計時,會命名一些變量名或函數名之類的符號。Linux內核是一個很復雜的代碼塊,有許許多多的全局符號, Linux內核不使用符號名,而是通過變量或函數的地址來識別變量或函數名,比如不是使用size_t BytesRead這樣的符號,而是像c0343f20這樣引用這個變量。 對於使用計算機的人來說,更喜歡使用那些像size_t BytesRead這樣的名字,而不喜歡像c0343f20這樣的名字。內核主要是用c寫的,所以編譯器/連接器允許我們編碼時使用符號名,而內核運行時使用地址。 然而,在有的情況下,我們需要知道符號的地址,或者需要知道地址對應的符號,這由符號表來完成,符號表是所有符號連同它們的地址的列表。
Linux 符號表使用到2個文件: /proc/ksyms 、System.map 。/proc/ksyms是一個“proc file”,在內核引導時創建。實際上,它並不真正的是一個文件,它只不過是內核數據的表示,卻給人們是一個磁盤文件的假象,這從它的文件大小是0可以看 出來。然而,System.map是存在於你的文件系統上的實際文件。當你編譯一個新內核時,各個符號名的地址要發生變化,你的老的System.map 具有的是錯誤的符號信息,每次內核編譯時產生一個新的System.map,你應當用新的System.map來取代老的System.map。
雖然內核本身並不真正使用System.map,但其它程序比如klogd, lsof和ps等軟件需要一個正確的System.map。如果你使用錯誤的或沒有System.map,klogd的輸出將是不可靠的,這對於排除程序故障會帶來困難。沒有System.map,你可能會面臨一些令人煩惱的提示信息。 另外少數驅動需要System.map來解析符號,沒有為你當前運行的特定內核創建的System.map它們就不能正常工作。 Linux的內核日志守護進程klogd為了執行名稱-地址解析,klogd需要使用System.map。System.map應當放在使用它的軟件能夠找到它的地方。執行:man klogd可知,如果沒有將System.map作為一個變量的位置給klogd,那么它將按照下面的順序,在三個地方查找System.map: /boot/System.map 、/System.map、/usr/src/linux/System.map
System.map也有版本信息,klogd能夠智能地查找正確的映象(map)文件。
(二)打包替換內核
打包替換新內核使用的是make-kpkg命令,所以此方法只適合支持make-kpkg命令的系統版本,一般適合Ubuntu、Debian等系統,不適合RedHat系統。
1、定制內核
#make mrprobe ,清理源代碼樹。
#make menuconfig ,配置內核。
2、打包內核
(1)拷貝.confg文件:
執行#cp /boot/config-,然后按下Tab鍵,系統會自動填上該目錄下符合條件的文件名,然后繼續輸入 .config,目的是使用在boot目錄下的原配置文件。
不執行這一步的話,后面make的時候會提示找不到.confg文件。
如果在上一步配置了內核的話應該是會自動生成.config文件,但這里本人只是執行了一次#make menuconfig命令並沒有配置內核。
(2)編譯打包內核
#make-kpkg --initrd - -append-to-version=-pyh - -revision=zxxiong.0716 -j 4kernel_image kernel_headers
執行完以上命令后將在上一級目錄生成兩個.deb包:
頭文件包:linux-headers-3.12.5-pyh_zxxiong.0716_amd64.deb
內核包:linux-image-3.12.5-pyh_zxxiong.0716_amd64.deb
【--initrd】選項會讓make-kpkg自動幫我們生成initramfs;
【--revision】會給生成的deb文件加上一個版本信息。這個參數只是影響到文件名,如果不指定,默認會是“10.00.Custom”;
【--append-to-version】也是一種版本信息,它不僅出現在deb安裝包的文件名里,也會影響到kernel的名稱,比如本例中,內核更新完成之后,用“uname -r”察看會得到“3.12.5-pyh”;
【kernel_image】表示生成內核和默認模塊的安裝包。
【kernel_headers】這樣make-kpkg會生成一個內核頭文件的安裝包。
如果我們用普通用戶來執行make-kpkg,需要加上fakeroot運行
| #fakeroot make-kpkg --initrd - -append-to-version=-pyh - -revision=zxxiong.0716 -j 4 kernel_image kernel_headers |
(注:需要設置平台 如-amd64在這里配置文件已經默認配置了,所以這里不用加,選項kernel_image是生成內核.deb包,選項kernel_headers是生成頭文件.deb包,這兩個選項可以只使用一個)
(3)安裝內核
將上面生成的.deb包拷貝到需要替換內核的機器上,執行以下命令:
#dpkg –i linux-headers-3.12.5-pyh_zxxiong.0716_amd64.deblinux-image-3.12.5-pyh_zxxiong.0716_amd64.deb (接上一行)
或者直接在deb包所在目錄執行:#dpkg –i ./*.deb
執行命令之后則會自動更新/boot目錄下的文件(即自動執行命令:# update-initramfs -c -k3.12.5 和#update-grub2),然后重啟系統並選定加載的內核就可以了,還可以修改/boot/grub/grub.cfg配置文件中的 set default=”0”, 默認為0,安裝完后查看該文件新加載的內核是第幾項就設置為幾(從0開始),這樣則不需要在開機時選擇啟動第幾項了。
(5) 重啟系統
#reboot
本文參考資料:
1、http://blog.csdn.net/cdsnmdl/article/details/3922513
2、http://blog.chinaunix.net/uid-26497520-id-3593098.html
注:如果覺得此文對您有所幫助,希望能鑒於博主打字的辛苦給個評論。當然更希望有錯誤之處能夠指正。
警告:轉載請標明出處 http://blog.csdn.net/star_xiong/article/details/17357821
