Linux 系統中, 用戶態到內核態切換的過程中發生了什麼?


一是中斷進入內核

二是異常進入內核

三是系統調用進入內核

拿x64來說,32位稍微有點不一樣。

內核可以設置6個不同的內核棧,用於不同的中斷,異常處理,這個是每個cpu一個的,不同cpu棧不一樣。

6個是cpu提供的功能,但內核沒有全部使用,調試異常,雙異常,有獨立的內核棧,其他異常共用一個內核棧,中斷又使用另外一個內核棧,即大概使用4個不同的棧。這樣設置是防止堆棧重入,比如中斷處理髮生異常,異常處理又發生異常,或者對中斷處理代碼設置斷點調試。

發生中斷跟異常的時候,根據相應中斷異常門的設置,切換內核堆棧,切換cs,許可權變成0級,即內核態。rip則改成門裡設置的值。

至於系統調用,現在用syscall/sysenter指令,在指令也會進入內核態,切換cs/rip,切換堆棧。這個設置有另外的寄存器設置,而不是通過門來設置。

具體到linux內核來說,每個cpu有256位元組的系統調用內核棧,發生系統調用時,先進入這個小棧,然後在系統調用處理入口完成內核堆棧切換,切換到該線程所屬內核棧中再進行處理。


問題很不完整啊。發生的事情可多著呢。

嗯,從問題的不完整度,反推,提問者應該是不理解:

「cpu異常」

以及相關的

「異常處理」

有關「CPU異常」這個概念的理解,讓我們先設想一種情況:當cpu想要讀0地址或者0xffffffff地址的時候,cpu會做什麼。

嗯,實際上,即使在不使用內存訪問控制來限制cpu內存訪問的情況下,這個動作都可能會導致未定義的結果。某些架構里cpu真的會嘗試去讀,然後把0填到你指定的寄存器里去。有些架構會嘗試在地址匯流排上發出信號,然後,因為等不到信號的處理者,所以CPU根本無法執行完這條指令。

「cpu異常」這個機制,就是設計出來應對這種事情的:有時候,CPU會收到一個執行不了,或者執行之後會導致問題,或者甚至是還不用執行就知道肯定執行之後會傷害系統的指令。這種情況下,CPU會認定自己發生了異常,然後(引入異常處理概念),跳轉到一段預設的地址,從預設地址處開始,重新執行代碼。

當然了,這套東西不是神造的,是cpu設計技術演進發展出來的。最最最古老的集成電路體系里肯定沒有這玩意。而現在每個CPU架構里都會有這個東西,各自有細節不同。intel的cpu在ring 3觸發異常後會切換自己狀態到ring 0並且開始以ring 0許可權執行異常錯誤處理代碼。arm則是跳到(超級用戶態?監督態?)一個特定狀態然後執行特定狀態入口處的處理代碼。

嗯,說了這麼多,還是在說「錯誤」。那麼系統調用呢?

「系統調用」體系是利用「CPU異常處理」而創造出的產物,然後也反過去影響了現代的cpu設計,進而又利用了cpu專門為系統調用做出的設計而進化出了現在我們看到的「系統調用」機制。

簡單滴說:以前CPU是遇到編寫不好的代碼然後觸發cpu狀態變化和異常處理,現在是cpu遇到預設的一個指令就開始切換cpu狀態並且跳轉到「系統調用(異常)」的處理入口。


有幾種情況會導致用戶態到內核態的切換:

硬體中斷,進程執行過程中,好比說用戶點擊了什麼按鈕,觸發了按鍵中斷,要趕緊去處理這個中斷啊,保存進程上下文,切換到中斷處理流程,處理完了,恢復進程上下文,返回用戶態(返回之前可能會進行進程調度,選擇一個更值得運行的進程投入運行態),進程繼續執行

系統調用,大多數處理器以一個中斷號來實現系統調用,所以處理過程和上面是一樣的


CPU從Ring3狀態進入Ring0狀態


推薦閱讀:

為什麼CPU/GPU的溫度會在一瞬間波動十度以上?
看手機CPU性能時,到底是單核跑分重要,還是多核跑分重要?
分散式計算下的一個共享經濟構思是否可行?
如何評價AMD在CES2018公布的桌面版Ryzen APU?
為什麼常聽說CPU屏蔽核心,而很少聽到GPU屏蔽核心?

TAG:操作系統 | 中央處理器CPU | Linux | Linux內核 |