一、Linux內核概覽
Linux是一個一體化內核(monolithic kernel)系統。
設備驅動程序可以完全訪問硬件。
Linux內的設備驅動程序可以方便地以模塊化(modularize)的形式設置,並在系統運行期間可直接裝載或卸載。
1. linux內核
linux操作系統是一個用來和硬件打交道並為用戶程序提供一個有限服務集的低級支撐軟件。
一個計算機系統是一個硬件和軟件的共生體,它們互相依賴,不可分割。
計算機的硬件,含有外圍設備、處理器、內存、硬盤和其他的電子設備組成計算機的發動機。
但是沒有軟件來操作和控制它,自身是不能工作的。
完成這個控制工作的軟件就稱為操作系統,在Linux的術語中被稱為“內核”,也可以稱為“核心”。
Linux內核的主要模塊(或組件)分以下幾個部分:
. 進程管理(process management)
. 定時器(timer)
. 中斷管理(interrupt management)
. 內存管理(memory management)
. 模塊管理(module management)
. 虛擬文件系統接口(VFS layer)
. 文件系統(file system)
. 設備驅動程序(device driver)
. 進程間通信(inter-process communication)
. 網絡管理(network management
. 系統啟動(system init)等操作系統功能的實現。
2. linux內核版本號
Linux內核使用三種不同的版本編號方式。
. 第一種方式用於1.0版本之前(包括1.0)。
第一個版本是0.01,緊接着是0.02、0.03、0.10、0.11、0.12、0.95、0.96、0.97、0.98、0.99和之后的1.0。
. 第二種方式用於1.0之后到2.6,數字由三部分“A.B.C”,A代表主版本號,B代表次主版本號,C代表較小的末版本號。
只有在內核發生很大變化時(歷史上只發生過兩次,1994年的1.0,1996年的2.0),A才變化。
可以通過數字B來判斷Linux是否穩定,偶數的B代表穩定版,奇數的B代表開發版。C代表一些bug修復,安全更新,新特性和驅動的次數。
以版本2.4.0為例,2代表主版本號,4代表次版本號,0代表改動較小的末版本號。
在版本號中,序號的第二位為偶數的版本表明這是一個可以使用的穩定版本,如2.2.5;
而序號的第二位為奇數的版本一般有一些新的東西加入,是個不一定很穩定的測試版本,如2.3.1。
這樣穩定版本來源於上一個測試版升級版本號,而一個穩定版本發展到完全成熟后就不再發展。
. 第三種方式從2004年2.6.0版本開始,使用一種“time-based”的方式。
3.0版本之前,是一種“A.B.C.D”的格式。
七年里,前兩個數字A.B即“2.6”保持不變,C隨着新版本的發布而增加,D代表一些bug修復,安全更新,添加新特性和驅動的次數。
3.0版本之后是“A.B.C”格式,B隨着新版本的發布而增加,C代表一些bug修復,安全更新,新特性和驅動的次數。
第三種方式中不使用偶數代表穩定版,奇數代表開發版這樣的命名方式。
舉個例子:3.7.0代表的不是開發版,而是穩定版!
linux內核升級時間圖譜如下:
linux內核版本的詳細表格如下(http://en.wikipedia.org/wiki/Linux_kernel#Version_numbering):
longterm support:提供長期支持的內核版本
stable: 穩定版本,而不是Beta測試版
關系就是:穩定版本不一定都提供長期支持,而提供長期支持的一定是穩定版本
3. linux發行版
Linux內核的發展過程中,我們還不得不提一下各種Linux發行版的作用,因為正是它們推動了Linux的應用,
從而也讓更多的人開始關注Linux。
一些組織或廠家,將Linux系統的內核與外圍實用程序(Utilities)軟件和文檔包裝起來,
並提供一些系統安裝界面和系統配置、設定與管理工具,就構成了一種發行版本(distribution),
Linux的發行版本其實就是Linux核心再加上外圍的實用程序組成的一個大軟件包而已。
相對於Linux操作系統內核版本,發行版本的版本號隨發布者的不同而不同,與Linux系統內核的版本號是相對獨立的。
因此把SUSE、RedHat、Ubuntu、Slackware等直接說成是Linux是不確切的,它們是Linux的發行版本,
更確切地說,應該叫做“以Linux為核心的操作系統軟件包”。
根據GPL准則,這些發行版本雖然都源自一個內核,並且都有自己各自的貢獻,但都沒有自己的版權。
Linux的各個發行版本(distribution),都是使用Linus主導開發並發布的同一個Linux內核,因此在內核層不存在什么兼容性問題。
每個版本都不一樣的感覺,只是在發行版本的最外層才有所體現,而絕不是Linux本身特別是內核不統一或是不兼容。
90年代初期Linux開始出現的時候,僅僅是以源代碼形式出現,用戶需要在其他操作系統下進行編譯才能使用。后來出現了一些正式版本。
目前最流行的幾個正式版本有:SUSE、RedHat、Fedora、Debian、Ubuntu、CentOS、Gentoo,等等。
用戶可根據自己的經驗和喜好選用合適的Linux發行版。
二、內核升級攻略
1. 查看linux內核版本:
# uname -r
2.6.18-194.el5
2. 下載新的內核版本:
去官網上下載最新的內核版本和對應的補丁:
https://www.kernel.org/
我選的是3.2.14
#wget -c http://www.kernel.org/pub/linux/kernel/v3.0/linux-3.2.14.tar.bz2
3. 解壓
將所需文件復制到 /usr/src 下並解壓。
(注:如果/usr/src下的空間不夠,將源文件放在別的目錄下也是一樣的)
# cp linux-3.2.14.tar.gz /usr/src/
# cd /usr/src/
將文件解壓到 /usr/src/kernels
# tar -xvf linux-3.2.14.tar.gz -C /usr/src/kernels
4. 清理文件
清除掉以前升級留下的一些不正確文件。
# cd /usr/src/kernels/linux-3.2.14
# yum install ncurses-devel #升級ncurses
# make mrporper
# cp /boot/config-‘uname -r’ /usr/src/kernels/linux3.2.14/.config #使用原來的配置文件
5. 通過菜單方式配置內核
# cd /usr/src/kernels/linux-3.2.14
# make menuconfig
linux配置菜單如下圖所示:
一定要勾選(輸入y選中,M編譯為模塊)
a、General setup→[*] enable deprecated sysfs features to support old userspace tools
b、Processor type and features→HighMemory Support。
c、找到以下選中選項並選中:
networking support → networking options → network packet filtering framework(netfilter)
(1)Corenetfilter configuration
. 勾中"Netfilter connection tracking support" -m state相關模塊是依賴它的,不選則沒有。
. 將netbios name service protocal support(new) 編譯成模塊,不然后面升級iptables后啟動時會出錯
. 勾中"Netfilter Xtables support (required for ip_tables)"
(2)IP: Netfilter Configuration
. 將 "IPv4 connection tracking support (require for NAT)" 編譯成模塊。
. 勾中IP tables support (required for filtering/masq/NAT) 。
. 將 "Full NAT" 下的 "MASQUERADE target support" 和 "REDIRECT target support" 編譯成模塊
6. 編譯並安裝內核
# make clean // 清除下內核編譯的目標文件
# make bzImage // 生成內核文件
# make modules // 編碼模塊
# make modules_install // 安裝模塊
# make install // 安裝
7. 編輯開機菜單選項grub文件
將 default=1 改為 default=0
# vim /etc/grub.conf
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE: You do not have a /boot partition. This means that
# all kernel and initrd paths are relative to /, eg.
# root (hd0,0)
# kernel /boot/vmlinuz-version ro root=/dev/sda1
# initrd /boot/initrd-version.img
#boot=/dev/sda
default=0
timeout=5
splashimage=(hd0,0)/boot/grub/splash.xpm.gz
hiddenmenu
title Red Hat Enterprise Linux Server (3.2.14)
root (hd0,0)
kernel /boot/vmlinuz-3.2.14 ro root=LABEL=/
initrd /boot/initrd-3.2.14.img
title Red Hat Enterprise Linux Server (2.6.18-274.el5)
root (hd0,0)
kernel /boot/vmlinuz-2.6.18-274.el5 ro root=LABEL=/
initrd /boot/initrd-2.6.18-274.el5.img
【保存並退出】
8. 重啟
# shutdown -r "now"
9. 查看內核編譯結果
# uname -r
3.2.14-rt24
三、內核編譯中遇到的錯誤及解決辦法
錯誤一、 編譯時出現錯誤提示
In file included from /usr/include/sys/time.h:31,
from /usr/include/linux/input.h:12,
from samples/hidraw/hid-example.c:14:
/usr/include/sys/select.h:78: error: conflicting types for 'fd_set'
/usr/include/linux/types.h:12: error: previous declaration of 'fd_set' was here
In file included from /usr/include/linux/input.h:14,
from samples/hidraw/hid-example.c:14:
/usr/include/sys/types.h:46: error: conflicting types for 'loff_t'
/usr/include/linux/types.h:30: error: previous declaration of 'loff_t' was here
/usr/include/sys/types.h:62: error: conflicting types for 'dev_t'
/usr/include/linux/types.h:13: error: previous declaration of 'dev_t' was here
In file included from /usr/include/sys/types.h:133,
from /usr/include/linux/input.h:14,
from samples/hidraw/hid-example.c:14:
/usr/include/time.h:105: error: conflicting types for 'timer_t'
/usr/include/linux/types.h:22: error: previous declaration of 'timer_t' was here
In file included from /usr/include/linux/input.h:14,
from samples/hidraw/hid-example.c:14:
/usr/include/sys/types.h:198: error: conflicting types for 'int64_t'
/usr/include/linux/types.h:98: error: previous declaration of 'int64_t' was here
/usr/include/sys/types.h:204: error: conflicting types for 'u_int64_t'
/usr/include/linux/types.h:97: error: previous declaration of 'u_int64_t' was here
In file included from /usr/include/linux/input.h:14,
from samples/hidraw/hid-example.c:14:
/usr/include/sys/types.h:235: error: conflicting types for 'blkcnt_t'
/usr/include/linux/types.h:114: error: previous declaration of 'blkcnt_t' was here
samples/hidraw/hid-example.c:15:26: error: linux/hidraw.h: No such file or directory
samples/hidraw/hid-example.c: In function 'main':
samples/hidraw/hid-example.c:48: error: storage size of 'rpt_desc' isn't known
samples/hidraw/hid-example.c:49: error: storage size of 'info' isn't known
samples/hidraw/hid-example.c:65: error: 'HIDIOCGRDESCSIZE' undeclared (first use in this function)
samples/hidraw/hid-example.c:65: error: (Each undeclared identifier is reported only once
samples/hidraw/hid-example.c:65: error: for each function it appears in.)
samples/hidraw/hid-example.c:73: error: 'HIDIOCGRDESC' undeclared (first use in this function)
samples/hidraw/hid-example.c:84: warning: implicit declaration of function 'HIDIOCGRAWNAME'
samples/hidraw/hid-example.c:91: warning: implicit declaration of function 'HIDIOCGRAWPHYS'
samples/hidraw/hid-example.c:98: error: 'HIDIOCGRAWINFO' undeclared (first use in this function)
samples/hidraw/hid-example.c:49: warning: unused variable 'info'
samples/hidraw/hid-example.c:48: warning: unused variable 'rpt_desc'
samples/hidraw/hid-example.c: In function 'bus_str':
samples/hidraw/hid-example.c:171: error: 'BUS_VIRTUAL' undeclared (first use in this function)
make[2]: *** [samples/hidraw/hid-example] Error 1
make[1]: *** [samples/hidraw] Error 2
make: *** [vmlinux] Error 2
解決方案:
# cp include/linux/hidraw.h /usr/include/linux/
# cp include/linux/hid.h /usr/include/linux/
# vim samples/hidraw/hid-example.c
(在Linux下編譯程序有時會遇到這種問題,這貌似是一個Linux歷史遺留問題:
把所有#include 都提到最前面,把#include 的包含放在其后,就可以編譯通過了,
之所以出現面的問題是存在循環引用所致。)
將13-15行的如下3行移動到33行以后。
13 #include
14 #include
15 #include
29 #include
30 #include
31 #include
32 #include
33 #include
【保存並退出】
# vim /usr/include/linux/input.h
line 647
#define BUS_PCI 0x01
#define BUS_ISAPNP 0x02
#define BUS_USB 0x03
#define BUS_HIL 0x04
#define BUS_BLUETOOTH 0x05
/*以下一行為新增*/
#define BUS_VIRTUAL 0x06
#define BUS_ISA 0x10
#define BUS_I8042 0x11
#define BUS_XTKBD 0x12
#define BUS_RS232 0x13
#define BUS_GAMEPORT 0x14
#define BUS_PARPORT 0x15
#define BUS_AMIGA 0x16
#define BUS_ADB 0x17
#define BUS_I2C 0x18
#define BUS_HOST 0x19
#define BUS_GSC 0x1A
/*以下兩行為新增*/
#define BUS_ATARI 0x1B
#define BUS_SPI 0x1C
【保存並退出】
再重新編譯;
錯誤二:
錯誤提示:Kernel panic—not syncing :vfs:unable to mount root fs on unkown—block (0,0)
錯誤分析:initrd-*.*.img文件有問題;未能成功掛載真正的根文件系統。
解決方法:請你確認執行了make install 命令,我就因為沒有執行這條命令而浪費了一周時間
錯誤三:
錯誤提示:Create root device mkrootdev: label / not found
Mountingrootfilesystem
mount :error2 mounting ext3
mount :error 2mountingnone
switch root mount failed:22
umount /initrd/dev failed :2
kernel panic-not synicncing :Attempted to kill init .
(錯誤提示是不是有點長,貌似錯誤很多哦,其實可能就一個原因導致)
錯誤分析:
1、根文件系統找不到掛載點 ,修改grub.conf文件為 root=/dev/ *
2、硬盤驅動未能找到,請看看你機器的硬盤是都是 SATA盤,是的話同樣恭喜你本文對你有幫助。
錯誤解決:
1.、修改grub.conf文件試試,具體修改點
root=/dev/*
* 指的是原系統中/分區的掛載點。修改后,重啟進入新內核系統,估計十有八九又會遇到如下錯誤提示:
Mounting root filesystem
mount :error6 mounting ext3
mount :error 2 mountingnone
switchroot mount failed:22
umount /initrd/dev failed :2
kernel panic-not synicncing :Attempted tokil linit .
如果不幸被我言中,請接着往下看。
2、硬盤驅動未能成功找到,SCSI驅動有問題。
我在內核編譯升級中遇到這個問題,對內核選項選了又選,方法試了很多種,錯誤依舊。
最終讓我無意中選正確選項,成功升級內核。
具體選項是:
Device Drivers--------SCSI
device support------SCSI
low-level drivers----Serial ATA(SATA)support 選為 M,
然后再選擇相應的子選項,我選擇了Intel PIIX/ICH SATA support (new)后機器就成功啟動了。
錯誤四:
錯誤提示:Enforcing mode requested but no policy loaded. Halting now.
kernel panic - not syncing: Attenpted to kill init!
錯誤分析:原內核中啟用了selinux,新內核未選擇selinux的選項,不能成功啟動。
解決方法:修改grub.conf文件,在root=LABEL=/ 后加入 enforcing=0
錯誤五:
編譯完重啟后出現:
switchroot: mount failed: 22
umount /initrd/dev failed: 2
kernel panic - not symcing: Attempted to kill init!
的錯誤,
解決辦法:
重新make menuconfig, 使CONFIG_SYSFS_DEPRECATED_V2=y
也可以打開文件.config做修改和驗證;
再執行:
# make bzImage
# make modules
# make modules_install
# make install
# shutdown -r "now"
四、linux內核啟動流程
計算機在啟動時都是先加電,
然后進行硬件檢測並引導操作系統的初始化程序,
然后操作系統的初始化程序程負責讀入系統內核並建產系統的運行環境.
一這過程相對來說比較復而且與CPU體系結構相關,這里我們通過linux並以i386的體系結構對這一過程進行較為詳細的說明.
1、硬件檢測
. 當機器加電后它首先執行BIOS(基本輸入輸出系統)中的代碼,BIOS首先執行加電自檢程序(POST),當自檢通過程便完成了硬件的啟動。
. POST程序通過對內存及其他硬件的設備的診斷檢測確定硬件的存在並可正確操作。
. BIOS是固化在芯片里的程序,執行這一過程一般只需要幾秒鍾。
. 當自檢完成后 BIOS按照系統COMS中設置的啟動順序搜尋有效的啟動驅動器(這里我們以硬盤為例),
並讀入系統引導扇區,並將系統控制權交給引導程序。
2、加載和執行引導程序
系統引導程序主要是把系統內核裝載到內存,啟動盤必須在第一個邏輯磁道上包含引導記錄。
這512個字節的扇區又被稱作是引導扇區,
在系統完成加電自檢后, BIOS從啟動盤中將引導扇區讀入到內存中。
引導記錄中包含了一些磁盤的物理特性的參數。
在引導扇區被讀入內存后,BIOS就能從這里讀取到啟動盤的物理參數。
一旦引導記錄加載完畢,BIOS就交出系統的執行控制權,跳轉到引導程序 的頭部執行。
引導記錄開頭是一條無條件轉移指令,它將立即跳轉到地址0x03e執行引導程序,
在引導扇區中這個引導程序將從磁盤中讀出其他幾個更為復雜的程序並由它們加載系統內核。
Linux的 引導程序由匯編代碼文件arch/i386/boot/bootsect.S生成,
它利用對BIOS功能的調用將 arch/i386/boot/下的setup.S文件和內核映象加載到內存。
i386的體系結構的CPU分保護模式和實模式兩種,在實模式下只能使用低端的640K內存。
系統在加載引導程序時CPU是處在實模式下,而現在的內核映象文件一般都超過了640K的限制,即使是經過壓縮過的內核映象,
這個內核映象文件通常是bzImage,我們在編譯內核時通常要用到這個文件。
由於bzImage超出了640K這一限制,所以linux設計了一個 bootsect_helper子程序(定義在arch/i386/boot/setup.S中),
引導程序通過循環調用bootsect_helper 將內核映象一塊一塊的裝入內存,當內核加載完畢,系統跳轉到setup.S的開始位置開始執行,
setup.S仍在實模式下運行,主要功能是設置系統參數 (如:內存、磁盤等),
並為進入保護模式做准備,最后進入到保護模式並跳轉到內核映象文件的頭部開始執行內核。
這里提一下有關linux的 引導程序 lilo和grub,lilo和grub可以引導多個系統,
如果機器上要裝多系統的話一般都會用到它們,這一引導程序也儲存在引導扇區中或者存放在主引導 記錄中(MBR),
lilo和grub都許允用戶自己配置,它們在系統安裝時建立了關於系統內核占用磁盤數據塊的位置對照表。
當用戶選擇啟動linux系統后,同樣也跳轉到setup.S上運行。
3、內核初始化
當setup.S執行完后,CPU進行保護模式,並開始執行內核,
. 如果內核是經過壓縮的,那么首先執行 arch/i386/boot/compressed目錄下的head.S建立堆棧並解壓內核映象文件,
然后再轉入arch/i386/kernel下的 head.S。
. 如果沒有壓縮則直接轉到arch/i386/kernel下的head.S開始執行。
arch/i386/kernel/head.S程序負責數據區(BBS)、中斷描述表(IDT)、段描述表(GDT)、頁表和寄存器的初始化。
最后進入start_kernel()模塊。
此時系統運行在內核模式(0級別)下,轉入到init/main.c中的start_kernel()。
start_kernel()繼續其他方面的初始化工作,主要是初始化系統的核心數據結構,主要包括:
setup_arch():執行與體系結構相關的設置。
trap_init():設置各種入口地址。
init_IRQ():初始化IRQ中斷處理機制。
sched_init():設置並啟動第一個進程init_task()。
softirq_init():對軟中斷子系統進行初始化。
console_init():初始化控制台、顯示器.
init_modules():初始化kernel_module。
fork_init():定義系統最大進程數.
最后進入rest_init()函數並調用kernel_thread()創建init內核線程,進行系統配置。
init內核線程占用進程描述表的第一項,由它來創建其他完成系統初始他的進程。
init內核線程首先要銷定內核,然后調用do_basic_setup()來初始化外部設備及加載驅動程序。
主要的初始化工作包括:
PCI總線初始化。
網絡初始化。
文件系統初始化。
加載文件系統。
在do_basic_setup()調用完成后,init()會釋放初始化函數據占用的內存,
並且打開/dev/console 設備重新定向控制台,用系統調用execve來執行用戶態程序/sbin/init。
至此,linux的內核初始化工作完成。
4. 下面的工作就由用戶態的/sbin/init程序來完成。
init程序程讀取/etc/inittab文件來決定它具體的工作。在inittab中比較重要的幾條是:
id:5:initdefault 決定操作系統啟動時缺省的執行級別(這里說講的是系統的運行級別,而不同於CPU的級別)
si:sysinit:/etc/rc.d/rc.sysinit 執行/etc/rc.d/rc.sysinit的腳本。
rc.sysinit主要的工作是 激活交換分區、檢查磁盤、加載硬件模塊。
1:2345:respawn:/sbin/mingetty tty1 顯示登錄界面
至此,整個系統的引導過程就完成了。