5分鍾搞懂kexec工作原理【轉】


轉自:https://zhuanlan.zhihu.com/p/105284305

什么是kexec?

可從當前正在運行的內核直接跳轉到新內核

為什么需要kexec?

跳過boot階段,減少重啟時間

kexec整體思路如下

1)新的kernel鏡像和initrd鏡像連續存儲在內存中,initrd的位置記錄在boot_params中

2)切換到新內核就是跳轉到新的kernel鏡像所在內存位置,CPU執行其entry的代碼即可,新的內核通過boot_params記錄的initrd位置完成根文件系統內容的加載

原理不復雜,但受到一些實際情況的限制,所以在實現上會略復雜一些。

首先,kernel鏡像有指定的入口地址,kernel鏡像要加載到入口地址位置才能正常啟動,而這塊內存正在被當前內核使用,所以kernel鏡像需要臨時存放的內存,在跳轉前要將內容搬移到入口地址。

其次,initrd的體積可能較大,找不到用於存儲initrd的連續大段物理內存,因此需要分散存儲在能申請到的內存頁面中,在kernel跳轉前搬移拼接到目的地址。

簡單講,鏡像先臨時存放,切換時再搬移到目標地址。

以kexec -s uImage --ramdisk=./ramdisk.bin為例進行說明。

uImage和ramdisk.bin都是要使用的內容,抽象為segment對象進行管理,那么這里存在2個segment,分別對應uImage和ramdisk.bin

內核使用alloc_pages來申請頁面,如果碎片化嚴重,很難申請到高階物理內存,所以kexec的做法是循環申請,每次申請一個頁面。這會帶來一個問題,屬於同一個鏡像的頁面彼此不連續,需要對這些臨時承載鏡像內容的頁面進行管理。

為此,kexec引入了entry的概念,其實就是一個unsigned long對象,記錄申請到的page的物理地址,並利用低位的4bit來對entry進行分類,共計有如下4類entry。

1)IND_DESTINATION,用於記錄segment要搬移到的目標地址

2)IND_SOURCE,用於記錄segment內容所在的物理地址

3)IND_INDIRECTION

4)IND_DONE

entry本身也需要內存來存儲,為此,kexec首先申請一個page用於存儲entry,如果page存滿entry時,需要再新分配一個page,並使用之前page內最后一個entry記錄新分配page的物理地址,這個entry就是3)IND_INDIRECTION類型entry。

那么uImage作為第一個segment,會對應一個IND_DESTINATION類型entry和若干IND_SOURCE類型entry,ramdisk.bin作為第二個segment同樣會對應一個IND_DESTINATION類型entry和若干IND_SOURCE類型entry,當全部segment存儲完成,kexec會加入4)IND_DONE類型entry,表示全部segment的內容到此記錄完成。

結合下圖會有較直觀的認識,IND_DESTINATION類型entry表示一個segment的開始,直到下一個IND_DESTINATION類型entry或IND_DONE類型entry之前的IND_SOURCE類型entry都記錄了該segment內容存儲的物理地址。

接下來的事情相對簡單,在用戶執行kexec -e后,會進入跳轉流程,將segment的內容依次搬移到IND_DESTINATION類型entry記錄的物理地址對應位置,結合下圖可有較直觀的認識。

全部segment內容搬移完成,跳轉到入口地址,就切換到了新的kernel。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM