㈠ 內核啟動流程
內核的初始化過程由start_kernel函數開始,至第一個用戶進程init結束,調用了一系列的初始化函數對所有的內核組件進行初始化。其中,start_kernel、rest_init、kernel_init、init_post等4個函數構成了整個初始化過程的主線。
從start_kernel函數開始,內核即進入了C語言部分,它完成了內核的大部分初始化工作。實際上,可以將start_kernel函數看做內核的main函數。
在start_kernel函數的最後調用了rest_init函數進行後續的初始化。
(1)rest_init中調用kernel_thread函數啟動了2個內核線程,分別是:kernel_init和kthreadd
(2)調用schele函數開啟了內核的調度系統,從此linux系統開始轉起來了。
rest_init最終調用cpu_idle函數結束了整個內核的啟動。
kernel_init函數將完成設備驅動程序的初始化,並調用init_post函數啟動用戶空間的init進程。
到init_post函數為止,內核的初始化已經進入尾聲,第一個用戶空間進程init將姍姍來遲
如果內核命令行中給出了到init進程的直接路徑(或者別的可替代的程序),這里就試圖執行init。
init:開始是內核態,後來轉變為用戶態】
init進程完成了從內核態向用戶態的轉變
init進程在內核態下面時,通過一個函數kernel_execve來執行一個用戶空間編譯連接的應用程序就跳躍到用戶態了。
在init/main.c中最後會通過kernel_execve()來調用用戶空間的init進程(如/sbin/init, /etc/init, /bin/init等
uboot通過傳參來告訴內核這些信息。
uboot傳參中的root=/dev/mmcblk0p2 rw 這一句就是告訴內核根文件系統在哪裡
uboot傳參中的rootfstype=ext3這一句就是告訴內核rootfs的類型。
㈡ 內核態和用戶態
內核態和用戶態是操作系統的兩種運行級別,內核態許可權高,用戶態許可權低。
用戶程序從用戶態切換到內核態:系統調用(軟中斷),異常,中斷。
系統調用是系統開放給用戶程序的介面。
庫函數是對系統調用的封裝。
shell也對系統調用進行了封裝。
系統調用,庫函數,shell是用戶程序主動訪問內核程序的三種方式。
參考: Linux | 為什麼用戶態和內核態的切換耗費時間? - JH_Zhai的博客 - CSDN博客
㈢ 用戶態與內核態
在計算機的指令中,引入了指令級別的概念,Window下分為0~3級,Linux下分為0、3兩級;
分級主要是為了區分不同的程序有不同的指令執行許可權;
在搞清楚用戶態與內核態之前,首先需要搞清楚,用戶態和內核態是針對誰描述的?
也看了網上不少資源,很多博客會直接對用戶態與內核態的區別直接上手做分析,但實際上了解這兩者是針對誰而言,對之後的學習也非常有效果。
這里用戶態與內核態是針對CPU而言的,是CPU的兩種運行狀態,也就是說再任意時刻CPU要麼處於內核態要麼處於用戶態。
這里的原因主要處於操作系統的安全性考慮;
設想一下,如果CPU沒有內核態與用戶態的概念,完全是一視同仁,所有用戶編寫的程序可以訪問一切硬體資源包括內存。這種情況下寫個病毒程序就太容易了,只要運行起來之後把內存的數據隨便遷移,這樣的場景對於整個系統安全性來說絕對是極其糟糕的。
因此來說,計算機所有硬體資源的使用權應該僅僅收回給操作系統,用戶態的程序無權進行訪問,如果用戶態的程序需要調用硬體資源如讀取網卡的數據,必須通過操作系統層面進行操作。
內核態程序執行完畢
我們都知道程序在執行的過程中是離不開棧的數據結構,操作系統在創建程序進程的同時會創建與該程序對應的兩個棧結構,分別用於用戶態程序執行與內核態程序執行。
當用戶態與內核態相互切換的時候,CPU要切換到不同的棧去執行程序,至於為什麼不能共用一個棧結構,多半也是為了安全考慮,分為兩個棧也就是兩片內存區域天然就有了隔離性,自然也就安全了。
本文大體描述了內核態與用戶態之間的聯系,但創作背景是在沒有完全看完權威的操作系統相關書籍情況下編寫。上述知識大多數來源於網路上的博客或B站視頻,可能其中存在不嚴謹的語句甚至錯誤,還請大家勘誤。
㈣ Linux用戶進程內核態執行,內核線程的關系問題
1、幾乎所有的程序都要切換到內核態運行再返回用戶態,用中斷完成的,因為在內核下封裝了一些東西,用戶態下只是傳入某些參數後調用內核態下的函數罷了,
2、進程有三態(執行態,就緒態,阻塞態),cpu任何時刻都只有一個進程在執行,so從用戶態切換到內核態時,用戶態下的進程就處於阻塞或就緒態了,至於從用戶態切換到內核態執行哪個函數那就看你在用戶態下執行的是什麼函數了,比如在用戶態下的lseek在內核下就是llseek了,不一樣的。
3、這問題就是linux的內存管理了,這里就得提到三種地址(邏輯地址、線性地址、物理地址),這里我們提到的4G地址是邏輯地址,不是我們實際的物理地址,linux中一個進程用戶佔0-3G對應的內核佔3G-4G部分
說得不是很清楚,這是比較復雜的內容,需要從頭看起,單就這幾個問題是不能搞懂linux的,最好還是系統的學習,不斷的重復
㈤ windows怎麼實現內核態和用戶態
為使用戶進程無法訪問甚至修改關鍵的操作系統數據,windows使用了兩種處理器訪問模式:用戶態和內核態。用戶應用代碼運行在用戶態,而系統代碼(如系統服務和設備驅動)運行在內核態。內核態指處理器中授權訪問所有系統內存並使用所有CPU指令的執行狀態。通過為操作系統軟體定義比用戶應用更高的特權,處理器的這種機制使操作系統設計者能夠保證行為無法捉摸的用戶應用程序不會破壞系統的穩定性。
雖然每個windows進程都有自己的私有地址空間,內核態的操作系統代碼和設備驅動代碼共享同一個虛擬地址空間。每個虛擬內存頁都設定了讀寫該頁所需要的處理器執行狀態。操作系統空間中的頁只有在內核態時才能訪問,所有用戶地址空間的頁都可以從用戶態訪問。只讀頁(通常存放的靜態數據)不管處理器處於什麼態都無法更改。另外,在支持不執行內存保護的處理器上,windows將包含數據的頁標記為不可執行,從而阻止無意觸發的對數據頁的代碼執行。
32位windows對在內核態運行的組件使用私有的系統內存不提供任何保護,也就是說一旦處於內核態,操作系統和設備驅動代碼對系統內存有完全的訪問許可權,並且能夠繞過window安全機制訪問對象。因為windows操作系統代碼運行在內核態,所以運行在內核態的組件需要精心設計並仔細測試以保證它們不會破壞系統安全從而引起系統不穩定。
缺少保護意味著在載入第三方驅動時需要十分小心,因為內核態的軟體對所有操作系統數據有完全的訪問許可權。windows的這一脆弱性也是其驅動簽名機制產生的重要原因,這一機制在系統添加未授權的驅動程序的時候會向用戶發出警告。同樣,一項稱為驅動驗證器(Driver
Verifier)的技術能夠幫助驅動程序編寫者查找bug(比如緩沖區溢出或者內存泄漏),以免引起安全或可靠性問題。
另外,64位windows中,內核模式代碼標記策略(KMCS)規定64位設備驅動必須使用從某一權威代碼認證機構獲取加密的key對驅動加以簽名。不像32位版本的windows,用戶不能公然強制安裝一個未授權的驅動,既使是管理員用戶(除非在啟動時按F8並選擇高級啟動選項關閉強制驅動簽名)
用戶應用作出系統調用時會從用戶態進入內核態。比如windows的ReadFile函數最終需要調用處理文件讀取的內核常式。這個常式由於訪問了內核系統數據結構必須運行的內核態下。從用戶態到內核態的轉換由一條特殊的將處理器轉換到內核態的處理器指令完成。操作系統捕獲這條指令,意識到有對系統服務的請求,驗證傳遞給系統函數的參數,然後執行內核函數。在將控制權交給用戶線程之前處理器返回用戶態。通過這種方式,系統保護自身數據以免被用戶進程讀取甚至修改。
因此,用戶線程部分時間在用戶態,部分時間在內核態。實際上,由於圖形和窗口系統代碼也運行在內核態,圖形密集型的應用在內核的時間會多於其在用戶態運行的時間。可使用性能工具監測圖形密集型應用的內核態和用戶態時間比例來測試。
可以使用windows自帶的性能監測器觀察系統在不同運行狀態下時間的比例。
步驟如下:
1 打開工具
2 點擊工具欄的 「+」
3 選擇處理器性能對象後,點擊%
Privileged Time計數器,然後按ctrl, 點 % User Time計數器
4 點擊 add
,然後點擊close
5 不斷在移動滑鼠,發現與上面分析一樣,%
Privileged Time迅速上升
㈥ 中斷服務程序都是運行在內核態嗎
最近復習操作系統和組成原理也遇到了這個問題,經過多方資料查詢,得到如下解釋:在中斷發生時,往往會先由中斷隱指令保存程序斷點,也就是pc(或pc+psw)里的內容(x86機器中psw的內容依然由隱指令即硬體保存,因為中斷服務程序可能會改變它的內容,MIPS中無psw,故只保存pc),這完全是由硬體實現的,然後需要調用中斷服務程序保存通用寄存器和中斷屏蔽字的內容,它由操作系統負責完成,運行在管態。
㈦ 系統調用是通過什麼方式陷入內核態的
第一步,在系統中添加一個不用傳遞參數的系統調用;執行這個系統調用,使用戶的uid等於0。顯然,這不是一個有實際意義的系統調用。我們的目的並不是實用不實用,而是通過最簡單的例子,幫助熟悉對系統調用的添加過程,為下面我們添加更加復雜的系統調用打好基礎。
第二步,用kernel mole機制,實現系統調用gettimeofday的簡化版,返回調用時刻的日期和時間。
實驗指導
1.一個簡單的例子
在我們開始學習系統調用這一章之前,讓我們先來看一個簡單的例子。就好像哪個經典的編程書上都會使用到的例子一樣:
1: int main(){
2: printf(「Hello World!\n」);
3: }
我們也准備了一個例子給你:
1: #include <linux/unistd.h> /* all system calls need this header */
2: int main(){
3: int i = getuid();
4: printf(「Hello World! This is my uid: %d\n」, i);
5: }
這就是一個最簡單的系統調用的例子。與上面那個傳統的例子相比,在這個例子中多了2行,他們的作用分別是:
第一行:包括unistd.h這個頭文件。所有用到系統調用的程序都需要包括它,因為系統調用中需要的參數(例如,本例中的「__NR_getuid」,以及_syscall0()函數)包括在unistd.h中;根據C語言的規定,include <linux/unistd.h>意味著/usr/include/linux目錄下整個unistd.h都屬於Hello World源程序了。
第三行:進行getuid()系統調用,並將返回值賦給變數i。
好了,這就是最簡單的一個使用了系統調用的程序,現在你可以在你的機器上試一試它。然後我們一起進入到系統調用的神秘世界中去。
㈧ 如何讓linux的一段程序代碼進入內核態運行
Linux內核的最初部分代碼是用匯編語言寫的(文件是boot/bootsect.s)。(我的匯編水平有限,暫且不看),它首先把自身這部分代碼移到絕對地址0x90000,把下面的2K代碼從引導設備載入到地址0x90200上,內核的其餘部分載入到地址0x10000處。在載入系統時顯示「loading...」. 然後,程序控制權交給另一個實模式匯編程序(boot/Setup.S)。
接下來,此程序把整個系統從地址0x10000移到地址0x1000,進入保護模式。程序控制轉給系統的其餘部分即地址0x1000。
下一個步驟是系統內核的解壓過程,這部分代碼在地址0x1000(文件/Boot/head.S),該段程序初始化寄存器,然後執行decompress_kernel(),這個函數源於zBoot/inflate.c、zBoot/unzip.c和zBoot/misc.c三個文件
Loading....[bootsect.S]
uncompress.....[decompress_kernel()]
main.c--->start_kernel()開始.
開始printk(banner);
Linuxversion2.2.6(root@lance)(gccversion2.7.2.3)(檢查一下GCC的版本號,在/init/main.c中如果gcc的版本號不夠,時不允許編譯內核的)
#40SunApr1817:44:20CST1999
調用init_time()列印出以下內容:
Detected199908264Hzprocessor.
然後運行console_init()-->drivers/char/tty_io.c*/
Console:colourVGA+80x25
運行一個循環,測量一下MIPS–據說是要用一個確定的機器指令周期來實現實時的延遲.
Calibratingdelayloop...199.48BogoMIPS
初始化內存/*init_mem*/
Memory:63396k/65536kavailable(848kkernelcode,408kreserved,856kdata
,28k
/**dquote_init()**/
VFS:Diskquotasversiondquot_6.4.0initialized
察看cpu的類型(在2.2.14以後聽說增加了對多種cpu的支持,以後我可得用心看看,ifIcanfindabugofintelthen……)
CPU:IntelPentiumProstepping09
初始或處理器與協處理器,對於比較老的處理器,linux會用軟體模擬協處理器?
Checking386/387coupling...OK,.
檢查治理的合法性
Checking'hlt'instruction...OK.
此後調用linux_thread(init,..,..,)(arch/i386/kernel/process.c)
創建一個運行init的進程.
進入了第二階段用戶模式(user_mode)Endofstart_kerne最後進入cpu_idle(arch/i386/kernel/process.c)
第二部分設備的初始化
對設備的初始化調用.init()--->do_basic_init()--+
pci_init()對pci設備的初始化(在main.c文件中有這樣一段ifdefPCI…..需要看一下)下面列印出結果:
PCI:PCIBIOSrevision2.10entryat0xfd8d1
PCI:Usingconfigurationtype1
PCI:ProbingPCIhardware
對Socket的初始化,socket_init()(這里也許就是linux的網路秘密所在吧,以後我的注意)-LinuxNET4.0forLinux2.2
.039
NET4:Unixdomainsockets1.0forLinuxNET4.0.
NET4:LinuxTCP/IP1.0forNET4.0
IPProtocols:ICMP,UDP,TCP
Startingkswapdv1.5kswapd_setup()
調用device_setup()
DetectedPS/2MousePort.
初始化音效卡
Soundinitializationstarted
Soundinitializationcomplete
初始化軟碟機
Floppydrive(s):fd0is1.44M
SCSI設備的初始化
(scsi0)foundatPCI13/0
(scsi0)WideChannel,SCSIID=7,16/255SCBs
(scsi0)Downloadingsequencercode...419instructionsdownloaded
scsi0:AdaptecAHA274x/284x/294x(EISA/VLB/PCI-FastSCSI)5.1.10/3.2.4
scsi:1host.
Vendor:SEAGATEModel:ST32155WRev:0596
ype:Direct-AccessANSISCSIrevision:02
Detectedscsidisksdaatscsi0,channel0,id0,lun0
Vendor:SEAGATEModel:ST32155WRev:0596
Type:Direct-AccessANSISCSIrevision:02
Detectedscsidisksdbatscsi0,channel0,id1,lun0
scsi:detected2SCSIdiskstotal.
(scsi0:0:0:0)Synchronousat40.0Mbyte/sec,offset8.
SCSIdevicesda:hdwrsector=512bytes.Sectors=4197405[2049MB][2.0GB](scsi0:0:1:0)Synchronousat40.0Mbyte/sec,offset8.
SCSIdevicesdb:hdwrsector=512bytes.Sectors=4197405[2049MB][2.0GB]Partitioncheck:sda:sda1|
sdb:sdb1sdb2|
安裝文件系統filesystem_setup()
安裝設備驅動程序mount_root()
VFS:Mountedroot(ext2filesystem)readonly.
Freeingunusedkernelmemory:28kfreed
AddingSwap:66540kswap-space(priority-1)
(C)byHannuSavolainen1993-1996
SB3.01detectedOK(220)
at0x220irq5dma1
YM3812andOPL-3driverCopyright(C)byHannuSavolainen,RobHooft1993-1
996at0x388
NET4:AppleTalk0.18forLinuxNET4.0
eth0:IntelEtherExpressPro10/100at0xf800,00:A0:C9:49:2F:FF,IRQ9.
Boardassembly645520-034,Physicalconnectorspresent:RJ45
#1.
DP83840specificsetup,settingregister23to8462.
Generalself-test:passed.
Serialsub-systemself-test:passed.
Internalregistersself-test:passed.
ROMchecksumself-test:passed(0x49caa8d6).
Receiverlock-upworkaroundactivated.
NET4:AppleTalk0.18forLinuxNET4.0
結束do_basic_setup()
open("/dev/console",O_RDWR,0)
開始執行/sbin/init(execv(...))
內核就此啟動完畢...
㈨ 內核態與用戶態
當程序運行在內核空間時為內核態,當程序運行在用戶空間時為用戶態。用戶態只能訪問用戶空間下的地址,而內核態可以訪問所有地址。
為防止用戶程序對系統造成破壞,所以限制用戶態程序訪問其他內存。
內核態程序執行完成後返回發起調用的用戶空間。
所有程序的用戶空間是獨立的,內核空間確是共享的,通過共享的內核空間實現程序間的數據交互。例如:MMAP。
狀態切換需要上下文切換(切換進程),消耗較大。
2022-03-27
㈩ 如何從應用程序進入linux內核
需要讓linux的一段程序代碼進入內核態運行產生的方式有二: 被動式 主動式 所謂被動式就是產生中斷或者代碼產出異常,代碼不得不從用戶態進入內核態進行中斷操作或者是異常處理; 而主動式則是系統響應了程序對系統的一次調用過程,並且系統允許該運行級別的提升;